2025-07-24 20:29:10 -04:00
|
|
|
//! High-performance Rust client for Polymarket
|
2025-12-05 19:09:06 -05:00
|
|
|
//!
|
2025-07-24 20:29:10 -04:00
|
|
|
//! This module provides a production-ready client for interacting with
|
|
|
|
|
//! Polymarket, optimized for high-frequency trading environments.
|
|
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
use crate::auth::{create_l1_headers, create_l2_headers};
|
2025-07-24 20:29:10 -04:00
|
|
|
use crate::errors::{PolyfillError, Result};
|
2025-12-05 19:09:06 -05:00
|
|
|
use crate::http_config::{
|
|
|
|
|
create_colocated_client, create_internet_client, create_optimized_client, prewarm_connections,
|
|
|
|
|
};
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
use crate::types::{OrderOptions, PostOrder, SignedOrderRequest};
|
|
|
|
|
use alloy_primitives::U256;
|
|
|
|
|
use alloy_signer_local::PrivateKeySigner;
|
|
|
|
|
use reqwest::header::HeaderName;
|
2025-12-05 19:09:06 -05:00
|
|
|
use reqwest::Client;
|
|
|
|
|
use reqwest::{Method, RequestBuilder};
|
|
|
|
|
use rust_decimal::prelude::FromPrimitive;
|
|
|
|
|
use rust_decimal::Decimal;
|
|
|
|
|
use serde_json::Value;
|
|
|
|
|
use std::str::FromStr;
|
2025-07-24 20:29:10 -04:00
|
|
|
|
|
|
|
|
// Re-export types for compatibility
|
2025-12-05 19:09:06 -05:00
|
|
|
pub use crate::types::{ApiCredentials as ApiCreds, OrderType, Side};
|
2025-07-24 20:29:10 -04:00
|
|
|
|
|
|
|
|
// Compatibility types
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct OrderArgs {
|
|
|
|
|
pub token_id: String,
|
|
|
|
|
pub price: Decimal,
|
|
|
|
|
pub size: Decimal,
|
|
|
|
|
pub side: Side,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl OrderArgs {
|
|
|
|
|
pub fn new(token_id: &str, price: Decimal, size: Decimal, side: Side) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
token_id: token_id.to_string(),
|
|
|
|
|
price,
|
|
|
|
|
size,
|
|
|
|
|
side,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for OrderArgs {
|
|
|
|
|
fn default() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
token_id: "".to_string(),
|
|
|
|
|
price: Decimal::ZERO,
|
|
|
|
|
size: Decimal::ZERO,
|
|
|
|
|
side: Side::BUY,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Main client for interacting with Polymarket API
|
|
|
|
|
pub struct ClobClient {
|
2025-12-06 17:19:02 -05:00
|
|
|
pub http_client: Client,
|
|
|
|
|
pub base_url: String,
|
2025-07-24 20:29:10 -04:00
|
|
|
chain_id: u64,
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
signer: Option<PrivateKeySigner>,
|
|
|
|
|
api_creds: Option<ApiCreds>,
|
|
|
|
|
order_builder: Option<crate::orders::OrderBuilder>,
|
2025-12-17 19:34:22 -05:00
|
|
|
#[allow(dead_code)]
|
2025-12-06 17:47:35 -05:00
|
|
|
dns_cache: Option<std::sync::Arc<crate::dns_cache::DnsCache>>,
|
2025-12-17 19:34:22 -05:00
|
|
|
#[allow(dead_code)]
|
2025-12-06 17:47:35 -05:00
|
|
|
connection_manager: Option<std::sync::Arc<crate::connection_manager::ConnectionManager>>,
|
2025-12-17 19:34:22 -05:00
|
|
|
#[allow(dead_code)]
|
2025-12-06 17:47:35 -05:00
|
|
|
buffer_pool: std::sync::Arc<crate::buffer_pool::BufferPool>,
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ClobClient {
|
2025-12-06 17:19:02 -05:00
|
|
|
/// Create a new client with optimized HTTP/2 settings (benchmarked 11.4% faster)
|
2025-12-06 17:47:35 -05:00
|
|
|
/// Now includes DNS caching, connection management, and buffer pooling
|
2025-07-24 20:29:10 -04:00
|
|
|
pub fn new(host: &str) -> Self {
|
2025-12-06 17:19:02 -05:00
|
|
|
// Benchmarked optimal configuration: 512KB stream window
|
|
|
|
|
// Results: 309.3ms vs 349ms baseline (11.4% improvement)
|
|
|
|
|
let optimized_client = reqwest::ClientBuilder::new()
|
|
|
|
|
.http2_adaptive_window(true)
|
|
|
|
|
.http2_initial_stream_window_size(512 * 1024) // 512KB - empirically optimal
|
|
|
|
|
.tcp_nodelay(true)
|
|
|
|
|
.pool_max_idle_per_host(10)
|
|
|
|
|
.pool_idle_timeout(std::time::Duration::from_secs(90))
|
|
|
|
|
.build()
|
|
|
|
|
.unwrap_or_else(|_| Client::new());
|
|
|
|
|
|
2025-12-06 17:47:35 -05:00
|
|
|
// Initialize DNS cache and pre-warm it
|
2025-12-17 19:34:22 -05:00
|
|
|
let dns_cache = tokio::runtime::Handle::try_current().ok().and_then(|_| {
|
|
|
|
|
tokio::task::block_in_place(|| {
|
|
|
|
|
tokio::runtime::Handle::current().block_on(async {
|
|
|
|
|
let cache = crate::dns_cache::DnsCache::new().await.ok()?;
|
|
|
|
|
let hostname = host
|
|
|
|
|
.trim_start_matches("https://")
|
|
|
|
|
.trim_start_matches("http://")
|
|
|
|
|
.split('/')
|
|
|
|
|
.next()?;
|
|
|
|
|
cache.prewarm(hostname).await.ok()?;
|
|
|
|
|
Some(std::sync::Arc::new(cache))
|
2025-12-06 17:47:35 -05:00
|
|
|
})
|
2025-12-17 19:34:22 -05:00
|
|
|
})
|
|
|
|
|
});
|
2025-12-06 17:47:35 -05:00
|
|
|
|
|
|
|
|
// Initialize connection manager
|
|
|
|
|
let connection_manager = Some(std::sync::Arc::new(
|
|
|
|
|
crate::connection_manager::ConnectionManager::new(
|
|
|
|
|
optimized_client.clone(),
|
|
|
|
|
host.to_string(),
|
|
|
|
|
),
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
// Initialize buffer pool (512KB buffers, pool of 10)
|
|
|
|
|
let buffer_pool = std::sync::Arc::new(crate::buffer_pool::BufferPool::new(512 * 1024, 10));
|
2025-12-17 19:34:22 -05:00
|
|
|
|
2025-12-06 17:47:35 -05:00
|
|
|
// Pre-warm buffer pool with 3 buffers
|
|
|
|
|
let pool_clone = buffer_pool.clone();
|
|
|
|
|
if let Ok(_handle) = tokio::runtime::Handle::try_current() {
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
pool_clone.prewarm(3).await;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-24 20:29:10 -04:00
|
|
|
Self {
|
2025-12-06 17:19:02 -05:00
|
|
|
http_client: optimized_client,
|
2025-07-24 20:29:10 -04:00
|
|
|
base_url: host.to_string(),
|
|
|
|
|
chain_id: 137, // Default to Polygon
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
signer: None,
|
|
|
|
|
api_creds: None,
|
|
|
|
|
order_builder: None,
|
2025-12-06 17:47:35 -05:00
|
|
|
dns_cache,
|
|
|
|
|
connection_manager,
|
|
|
|
|
buffer_pool,
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-04 06:35:12 -05:00
|
|
|
/// Create a client optimized for co-located environments
|
|
|
|
|
pub fn new_colocated(host: &str) -> Self {
|
2025-12-06 17:47:35 -05:00
|
|
|
let http_client = create_colocated_client().unwrap_or_else(|_| Client::new());
|
2025-12-17 19:34:22 -05:00
|
|
|
|
2025-12-06 17:47:35 -05:00
|
|
|
let connection_manager = Some(std::sync::Arc::new(
|
|
|
|
|
crate::connection_manager::ConnectionManager::new(
|
|
|
|
|
http_client.clone(),
|
|
|
|
|
host.to_string(),
|
|
|
|
|
),
|
|
|
|
|
));
|
|
|
|
|
let buffer_pool = std::sync::Arc::new(crate::buffer_pool::BufferPool::new(512 * 1024, 10));
|
2025-12-17 19:34:22 -05:00
|
|
|
|
2025-12-04 06:35:12 -05:00
|
|
|
Self {
|
2025-12-06 17:47:35 -05:00
|
|
|
http_client,
|
2025-12-04 06:35:12 -05:00
|
|
|
base_url: host.to_string(),
|
|
|
|
|
chain_id: 137,
|
|
|
|
|
signer: None,
|
|
|
|
|
api_creds: None,
|
|
|
|
|
order_builder: None,
|
2025-12-06 17:47:35 -05:00
|
|
|
dns_cache: None,
|
|
|
|
|
connection_manager,
|
|
|
|
|
buffer_pool,
|
2025-12-04 06:35:12 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create a client optimized for internet connections
|
|
|
|
|
pub fn new_internet(host: &str) -> Self {
|
2025-12-06 17:47:35 -05:00
|
|
|
let http_client = create_internet_client().unwrap_or_else(|_| Client::new());
|
2025-12-17 19:34:22 -05:00
|
|
|
|
2025-12-06 17:47:35 -05:00
|
|
|
let connection_manager = Some(std::sync::Arc::new(
|
|
|
|
|
crate::connection_manager::ConnectionManager::new(
|
|
|
|
|
http_client.clone(),
|
|
|
|
|
host.to_string(),
|
|
|
|
|
),
|
|
|
|
|
));
|
|
|
|
|
let buffer_pool = std::sync::Arc::new(crate::buffer_pool::BufferPool::new(512 * 1024, 10));
|
2025-12-17 19:34:22 -05:00
|
|
|
|
2025-12-04 06:35:12 -05:00
|
|
|
Self {
|
2025-12-06 17:47:35 -05:00
|
|
|
http_client,
|
2025-12-04 06:35:12 -05:00
|
|
|
base_url: host.to_string(),
|
|
|
|
|
chain_id: 137,
|
|
|
|
|
signer: None,
|
|
|
|
|
api_creds: None,
|
|
|
|
|
order_builder: None,
|
2025-12-06 17:47:35 -05:00
|
|
|
dns_cache: None,
|
|
|
|
|
connection_manager,
|
|
|
|
|
buffer_pool,
|
2025-12-04 06:35:12 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// Create a client with L1 headers (for authentication)
|
|
|
|
|
pub fn with_l1_headers(host: &str, private_key: &str, chain_id: u64) -> Self {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = private_key
|
|
|
|
|
.parse::<PrivateKeySigner>()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.expect("Invalid private key");
|
2025-12-05 19:09:06 -05:00
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
let order_builder = crate::orders::OrderBuilder::new(signer.clone(), None, None);
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-12-06 17:47:35 -05:00
|
|
|
let http_client = create_optimized_client().unwrap_or_else(|_| Client::new());
|
2025-12-17 19:34:22 -05:00
|
|
|
|
2025-12-06 17:47:35 -05:00
|
|
|
// Initialize infrastructure modules
|
|
|
|
|
let dns_cache = None; // Skip DNS cache for simplicity in this constructor
|
|
|
|
|
let connection_manager = Some(std::sync::Arc::new(
|
|
|
|
|
crate::connection_manager::ConnectionManager::new(
|
|
|
|
|
http_client.clone(),
|
|
|
|
|
host.to_string(),
|
|
|
|
|
),
|
|
|
|
|
));
|
|
|
|
|
let buffer_pool = std::sync::Arc::new(crate::buffer_pool::BufferPool::new(512 * 1024, 10));
|
|
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
Self {
|
2025-12-06 17:47:35 -05:00
|
|
|
http_client,
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
base_url: host.to_string(),
|
|
|
|
|
chain_id,
|
|
|
|
|
signer: Some(signer),
|
|
|
|
|
api_creds: None,
|
|
|
|
|
order_builder: Some(order_builder),
|
2025-12-06 17:47:35 -05:00
|
|
|
dns_cache,
|
|
|
|
|
connection_manager,
|
|
|
|
|
buffer_pool,
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-04 18:55:20 -05:00
|
|
|
/// Create a client with L2 headers (for API key authentication)
|
2025-12-05 19:09:06 -05:00
|
|
|
pub fn with_l2_headers(
|
|
|
|
|
host: &str,
|
|
|
|
|
private_key: &str,
|
|
|
|
|
chain_id: u64,
|
|
|
|
|
api_creds: ApiCreds,
|
|
|
|
|
) -> Self {
|
|
|
|
|
let signer = private_key
|
|
|
|
|
.parse::<PrivateKeySigner>()
|
2025-11-04 18:55:20 -05:00
|
|
|
.expect("Invalid private key");
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 18:55:20 -05:00
|
|
|
let order_builder = crate::orders::OrderBuilder::new(signer.clone(), None, None);
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-12-06 17:47:35 -05:00
|
|
|
let http_client = create_optimized_client().unwrap_or_else(|_| Client::new());
|
2025-12-17 19:34:22 -05:00
|
|
|
|
2025-12-06 17:47:35 -05:00
|
|
|
// Initialize infrastructure modules
|
|
|
|
|
let dns_cache = None; // Skip DNS cache for simplicity in this constructor
|
|
|
|
|
let connection_manager = Some(std::sync::Arc::new(
|
|
|
|
|
crate::connection_manager::ConnectionManager::new(
|
|
|
|
|
http_client.clone(),
|
|
|
|
|
host.to_string(),
|
|
|
|
|
),
|
|
|
|
|
));
|
|
|
|
|
let buffer_pool = std::sync::Arc::new(crate::buffer_pool::BufferPool::new(512 * 1024, 10));
|
|
|
|
|
|
2025-11-04 18:55:20 -05:00
|
|
|
Self {
|
2025-12-06 17:47:35 -05:00
|
|
|
http_client,
|
2025-11-04 18:55:20 -05:00
|
|
|
base_url: host.to_string(),
|
|
|
|
|
chain_id,
|
|
|
|
|
signer: Some(signer),
|
|
|
|
|
api_creds: Some(api_creds),
|
|
|
|
|
order_builder: Some(order_builder),
|
2025-12-06 17:47:35 -05:00
|
|
|
dns_cache,
|
|
|
|
|
connection_manager,
|
|
|
|
|
buffer_pool,
|
2025-11-04 18:55:20 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// Set API credentials
|
|
|
|
|
pub fn set_api_creds(&mut self, api_creds: ApiCreds) {
|
|
|
|
|
self.api_creds = Some(api_creds);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-06 17:47:35 -05:00
|
|
|
/// Start background keep-alive to maintain warm connection
|
|
|
|
|
/// Sends periodic lightweight requests to prevent connection drops
|
|
|
|
|
pub async fn start_keepalive(&self, interval: std::time::Duration) {
|
|
|
|
|
if let Some(manager) = &self.connection_manager {
|
|
|
|
|
manager.start_keepalive(interval).await;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Stop keep-alive background task
|
|
|
|
|
pub async fn stop_keepalive(&self) {
|
|
|
|
|
if let Some(manager) = &self.connection_manager {
|
|
|
|
|
manager.stop_keepalive().await;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-04 06:35:12 -05:00
|
|
|
/// Pre-warm connections to reduce first-request latency
|
|
|
|
|
pub async fn prewarm_connections(&self) -> Result<()> {
|
|
|
|
|
prewarm_connections(&self.http_client, &self.base_url)
|
|
|
|
|
.await
|
2025-12-05 19:09:06 -05:00
|
|
|
.map_err(|e| {
|
|
|
|
|
PolyfillError::network(format!("Failed to prewarm connections: {}", e), e)
|
|
|
|
|
})?;
|
2025-12-04 06:35:12 -05:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-04 02:36:33 -05:00
|
|
|
/// Get the wallet address
|
|
|
|
|
pub fn get_address(&self) -> Option<String> {
|
|
|
|
|
use alloy_primitives::hex;
|
2025-12-05 19:09:06 -05:00
|
|
|
self.signer
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|s| hex::encode_prefixed(s.address().as_slice()))
|
2025-12-04 02:36:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get the collateral token address for the current chain
|
|
|
|
|
pub fn get_collateral_address(&self) -> Option<String> {
|
|
|
|
|
let config = crate::orders::get_contract_config(self.chain_id, false)?;
|
|
|
|
|
Some(config.collateral)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get the conditional tokens contract address for the current chain
|
|
|
|
|
pub fn get_conditional_address(&self) -> Option<String> {
|
|
|
|
|
let config = crate::orders::get_contract_config(self.chain_id, false)?;
|
|
|
|
|
Some(config.conditional_tokens)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get the exchange contract address for the current chain
|
|
|
|
|
pub fn get_exchange_address(&self) -> Option<String> {
|
|
|
|
|
let config = crate::orders::get_contract_config(self.chain_id, false)?;
|
|
|
|
|
Some(config.exchange)
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-24 20:29:10 -04:00
|
|
|
/// Test basic connectivity
|
|
|
|
|
pub async fn get_ok(&self) -> bool {
|
2025-12-05 19:09:06 -05:00
|
|
|
match self
|
|
|
|
|
.http_client
|
|
|
|
|
.get(format!("{}/ok", self.base_url))
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
|
|
|
|
{
|
2025-07-24 20:29:10 -04:00
|
|
|
Ok(response) => response.status().is_success(),
|
|
|
|
|
Err(_) => false,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get server time
|
|
|
|
|
pub async fn get_server_time(&self) -> Result<u64> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:26:38 -05:00
|
|
|
.get(format!("{}/time", self.base_url))
|
2025-07-24 20:29:10 -04:00
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get server time",
|
|
|
|
|
));
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let time_text = response.text().await?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let timestamp = time_text
|
|
|
|
|
.trim()
|
2025-07-24 20:29:10 -04:00
|
|
|
.parse::<u64>()
|
|
|
|
|
.map_err(|e| PolyfillError::parse(format!("Invalid timestamp format: {}", e), None))?;
|
|
|
|
|
|
|
|
|
|
Ok(timestamp)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get order book for a token
|
|
|
|
|
pub async fn get_order_book(&self, token_id: &str) -> Result<OrderBookSummary> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/book", self.base_url))
|
2025-07-24 20:29:10 -04:00
|
|
|
.query(&[("token_id", token_id)])
|
|
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get order book",
|
|
|
|
|
));
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let order_book: OrderBookSummary = response.json().await?;
|
|
|
|
|
Ok(order_book)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get midpoint for a token
|
|
|
|
|
pub async fn get_midpoint(&self, token_id: &str) -> Result<MidpointResponse> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/midpoint", self.base_url))
|
2025-07-24 20:29:10 -04:00
|
|
|
.query(&[("token_id", token_id)])
|
|
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get midpoint",
|
|
|
|
|
));
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let midpoint: MidpointResponse = response.json().await?;
|
|
|
|
|
Ok(midpoint)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get spread for a token
|
|
|
|
|
pub async fn get_spread(&self, token_id: &str) -> Result<SpreadResponse> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/spread", self.base_url))
|
2025-07-24 20:29:10 -04:00
|
|
|
.query(&[("token_id", token_id)])
|
|
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get spread",
|
|
|
|
|
));
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let spread: SpreadResponse = response.json().await?;
|
|
|
|
|
Ok(spread)
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-04 23:03:55 -05:00
|
|
|
/// Get spreads for multiple tokens (batch)
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_spreads(
|
|
|
|
|
&self,
|
|
|
|
|
token_ids: &[String],
|
|
|
|
|
) -> Result<std::collections::HashMap<String, Decimal>> {
|
2025-11-04 23:03:55 -05:00
|
|
|
let request_data: Vec<std::collections::HashMap<&str, String>> = token_ids
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|id| {
|
|
|
|
|
let mut map = std::collections::HashMap::new();
|
|
|
|
|
map.insert("token_id", id.clone());
|
|
|
|
|
map
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.post(format!("{}/spreads", self.base_url))
|
2025-11-04 23:03:55 -05:00
|
|
|
.json(&request_data)
|
|
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get batch spreads",
|
|
|
|
|
));
|
2025-11-04 23:03:55 -05:00
|
|
|
}
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<std::collections::HashMap<String, Decimal>>()
|
|
|
|
|
.await
|
2025-11-04 23:03:55 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-24 20:29:10 -04:00
|
|
|
/// Get price for a token and side
|
|
|
|
|
pub async fn get_price(&self, token_id: &str, side: Side) -> Result<PriceResponse> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/price", self.base_url))
|
2025-12-05 19:09:06 -05:00
|
|
|
.query(&[("token_id", token_id), ("side", side.as_str())])
|
2025-07-24 20:29:10 -04:00
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get price",
|
|
|
|
|
));
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let price: PriceResponse = response.json().await?;
|
|
|
|
|
Ok(price)
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 10:30:48 -05:00
|
|
|
fn validate_prices_history_asset_id(asset_id: &str) -> Result<()> {
|
|
|
|
|
if asset_id.is_empty() {
|
|
|
|
|
return Err(PolyfillError::validation(
|
|
|
|
|
"asset_id is required (use the decimal token_id / asset_id)",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Common footgun: passing a condition id (0x...) instead of the decimal asset id.
|
|
|
|
|
if asset_id.starts_with("0x") || asset_id.starts_with("0X") {
|
|
|
|
|
return Err(PolyfillError::validation(
|
|
|
|
|
"`/prices-history` expects a decimal token_id/asset_id, not a hex condition_id",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !asset_id.as_bytes().iter().all(u8::is_ascii_digit) {
|
|
|
|
|
return Err(PolyfillError::validation(
|
|
|
|
|
"asset_id must be a decimal string (token_id / asset_id)",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get price history for a single outcome (`token_id` / `asset_id`) over a fixed interval.
|
|
|
|
|
///
|
|
|
|
|
/// Important: the upstream API query parameter is named `market`, but it expects the
|
|
|
|
|
/// decimal outcome asset id (not the hex `condition_id`).
|
|
|
|
|
pub async fn get_prices_history_interval(
|
|
|
|
|
&self,
|
|
|
|
|
asset_id: &str,
|
|
|
|
|
interval: PricesHistoryInterval,
|
|
|
|
|
fidelity: Option<u32>,
|
|
|
|
|
) -> Result<PricesHistoryResponse> {
|
|
|
|
|
Self::validate_prices_history_asset_id(asset_id)?;
|
|
|
|
|
|
|
|
|
|
let mut request = self
|
|
|
|
|
.http_client
|
|
|
|
|
.get(format!("{}/prices-history", self.base_url))
|
|
|
|
|
.query(&[("market", asset_id), ("interval", interval.as_str())]);
|
|
|
|
|
|
|
|
|
|
if let Some(fidelity) = fidelity {
|
|
|
|
|
request = request.query(&[("fidelity", fidelity)]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let response = request.send().await?;
|
|
|
|
|
if !response.status().is_success() {
|
|
|
|
|
let status = response.status().as_u16();
|
|
|
|
|
let body = response.text().await.unwrap_or_default();
|
|
|
|
|
let message = serde_json::from_str::<Value>(&body)
|
|
|
|
|
.ok()
|
|
|
|
|
.and_then(|v| {
|
|
|
|
|
v.get("error")
|
|
|
|
|
.and_then(Value::as_str)
|
|
|
|
|
.map(|s| s.to_string())
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
|
if body.is_empty() {
|
|
|
|
|
"Failed to get prices history".to_string()
|
|
|
|
|
} else {
|
|
|
|
|
body
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return Err(PolyfillError::api(status, message));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(response.json::<PricesHistoryResponse>().await?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get price history for a single outcome (`token_id` / `asset_id`) over a timestamp range.
|
|
|
|
|
///
|
|
|
|
|
/// `start_ts` and `end_ts` are Unix timestamps (seconds).
|
|
|
|
|
pub async fn get_prices_history_range(
|
|
|
|
|
&self,
|
|
|
|
|
asset_id: &str,
|
|
|
|
|
start_ts: u64,
|
|
|
|
|
end_ts: u64,
|
|
|
|
|
fidelity: Option<u32>,
|
|
|
|
|
) -> Result<PricesHistoryResponse> {
|
|
|
|
|
Self::validate_prices_history_asset_id(asset_id)?;
|
|
|
|
|
|
|
|
|
|
if start_ts >= end_ts {
|
|
|
|
|
return Err(PolyfillError::validation(
|
|
|
|
|
"start_ts must be < end_ts for prices history",
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let mut request = self
|
|
|
|
|
.http_client
|
|
|
|
|
.get(format!("{}/prices-history", self.base_url))
|
|
|
|
|
.query(&[("market", asset_id)])
|
|
|
|
|
.query(&[("startTs", start_ts), ("endTs", end_ts)]);
|
|
|
|
|
|
|
|
|
|
if let Some(fidelity) = fidelity {
|
|
|
|
|
request = request.query(&[("fidelity", fidelity)]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let response = request.send().await?;
|
|
|
|
|
if !response.status().is_success() {
|
|
|
|
|
let status = response.status().as_u16();
|
|
|
|
|
let body = response.text().await.unwrap_or_default();
|
|
|
|
|
let message = serde_json::from_str::<Value>(&body)
|
|
|
|
|
.ok()
|
|
|
|
|
.and_then(|v| {
|
|
|
|
|
v.get("error")
|
|
|
|
|
.and_then(Value::as_str)
|
|
|
|
|
.map(|s| s.to_string())
|
|
|
|
|
})
|
|
|
|
|
.unwrap_or_else(|| {
|
|
|
|
|
if body.is_empty() {
|
|
|
|
|
"Failed to get prices history".to_string()
|
|
|
|
|
} else {
|
|
|
|
|
body
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return Err(PolyfillError::api(status, message));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(response.json::<PricesHistoryResponse>().await?)
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-24 20:29:10 -04:00
|
|
|
/// Get tick size for a token
|
|
|
|
|
pub async fn get_tick_size(&self, token_id: &str) -> Result<Decimal> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/tick-size", self.base_url))
|
2025-07-24 20:29:10 -04:00
|
|
|
.query(&[("token_id", token_id)])
|
|
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get tick size",
|
|
|
|
|
));
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let tick_size_response: Value = response.json().await?;
|
|
|
|
|
let tick_size = tick_size_response["minimum_tick_size"]
|
|
|
|
|
.as_str()
|
|
|
|
|
.and_then(|s| Decimal::from_str(s).ok())
|
2025-12-05 19:09:06 -05:00
|
|
|
.or_else(|| {
|
|
|
|
|
tick_size_response["minimum_tick_size"]
|
|
|
|
|
.as_f64()
|
|
|
|
|
.map(|f| Decimal::from_f64(f).unwrap_or(Decimal::ZERO))
|
|
|
|
|
})
|
2025-07-24 20:29:10 -04:00
|
|
|
.ok_or_else(|| PolyfillError::parse("Invalid tick size format", None))?;
|
|
|
|
|
|
|
|
|
|
Ok(tick_size)
|
|
|
|
|
}
|
|
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// Create a new API key
|
|
|
|
|
pub async fn create_api_key(&self, nonce: Option<U256>) -> Result<ApiCreds> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
let headers = create_l1_headers(signer, nonce)?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let req =
|
|
|
|
|
self.create_request_with_headers(Method::POST, "/auth/api-key", headers.into_iter());
|
|
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
let response = req.send().await?;
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to create API key",
|
|
|
|
|
));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
2025-12-05 19:09:06 -05:00
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
Ok(response.json::<ApiCreds>().await?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Derive an existing API key
|
|
|
|
|
pub async fn derive_api_key(&self, nonce: Option<U256>) -> Result<ApiCreds> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
let headers = create_l1_headers(signer, nonce)?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let req = self.create_request_with_headers(
|
|
|
|
|
Method::GET,
|
|
|
|
|
"/auth/derive-api-key",
|
|
|
|
|
headers.into_iter(),
|
|
|
|
|
);
|
|
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
let response = req.send().await?;
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to derive API key",
|
|
|
|
|
));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
2025-12-05 19:09:06 -05:00
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
Ok(response.json::<ApiCreds>().await?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create or derive API key (try create first, fallback to derive)
|
|
|
|
|
pub async fn create_or_derive_api_key(&self, nonce: Option<U256>) -> Result<ApiCreds> {
|
|
|
|
|
match self.create_api_key(nonce).await {
|
|
|
|
|
Ok(creds) => Ok(creds),
|
2026-01-29 18:28:42 -05:00
|
|
|
// Only fall back to derive on API status errors (server responded).
|
|
|
|
|
// Propagate network/parse/internal errors so callers can handle them appropriately.
|
|
|
|
|
Err(PolyfillError::Api { .. }) => self.derive_api_key(nonce).await,
|
|
|
|
|
Err(err) => Err(err),
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-04 18:55:54 -05:00
|
|
|
/// Get all API keys for the authenticated user
|
|
|
|
|
pub async fn get_api_keys(&self) -> Result<Vec<String>> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
2025-11-04 18:55:54 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("Signer not configured"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
2025-11-04 18:55:54 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("API credentials not configured"))?;
|
|
|
|
|
|
|
|
|
|
let method = Method::GET;
|
|
|
|
|
let endpoint = "/auth/api-keys";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
2025-11-04 18:55:54 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 18:55:54 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 18:55:54 -05:00
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 18:55:54 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_keys_response: crate::types::ApiKeysResponse = response
|
|
|
|
|
.json()
|
|
|
|
|
.await
|
2025-11-04 18:55:54 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))?;
|
|
|
|
|
|
|
|
|
|
Ok(api_keys_response.api_keys)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Delete the current API key
|
|
|
|
|
pub async fn delete_api_key(&self) -> Result<String> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
2025-11-04 18:55:54 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("Signer not configured"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
2025-11-04 18:55:54 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("API credentials not configured"))?;
|
|
|
|
|
|
|
|
|
|
let method = Method::DELETE;
|
|
|
|
|
let endpoint = "/auth/api-key";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
2025-11-04 18:55:54 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 18:55:54 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 18:55:54 -05:00
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 18:55:54 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.text()
|
|
|
|
|
.await
|
2025-11-04 18:55:54 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// Helper to create request with headers
|
|
|
|
|
fn create_request_with_headers(
|
|
|
|
|
&self,
|
|
|
|
|
method: Method,
|
|
|
|
|
endpoint: &str,
|
|
|
|
|
headers: impl Iterator<Item = (&'static str, String)>,
|
|
|
|
|
) -> RequestBuilder {
|
2025-12-05 19:09:06 -05:00
|
|
|
let req = self
|
|
|
|
|
.http_client
|
|
|
|
|
.request(method, format!("{}{}", &self.base_url, endpoint));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
headers.fold(req, |r, (k, v)| r.header(HeaderName::from_static(k), v))
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-24 20:29:10 -04:00
|
|
|
/// Get neg risk for a token
|
|
|
|
|
pub async fn get_neg_risk(&self, token_id: &str) -> Result<bool> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/neg-risk", self.base_url))
|
2025-07-24 20:29:10 -04:00
|
|
|
.query(&[("token_id", token_id)])
|
|
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get neg risk",
|
|
|
|
|
));
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let neg_risk_response: Value = response.json().await?;
|
|
|
|
|
let neg_risk = neg_risk_response["neg_risk"]
|
|
|
|
|
.as_bool()
|
|
|
|
|
.ok_or_else(|| PolyfillError::parse("Invalid neg risk format", None))?;
|
|
|
|
|
|
|
|
|
|
Ok(neg_risk)
|
|
|
|
|
}
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
|
|
|
|
|
/// Resolve tick size for an order
|
|
|
|
|
async fn resolve_tick_size(
|
|
|
|
|
&self,
|
|
|
|
|
token_id: &str,
|
|
|
|
|
tick_size: Option<Decimal>,
|
|
|
|
|
) -> Result<Decimal> {
|
|
|
|
|
let min_tick_size = self.get_tick_size(token_id).await?;
|
|
|
|
|
|
|
|
|
|
match tick_size {
|
|
|
|
|
None => Ok(min_tick_size),
|
|
|
|
|
Some(t) => {
|
|
|
|
|
if t < min_tick_size {
|
|
|
|
|
Err(PolyfillError::validation(format!(
|
|
|
|
|
"Tick size {} is smaller than min_tick_size {} for token_id: {}",
|
|
|
|
|
t, min_tick_size, token_id
|
|
|
|
|
)))
|
|
|
|
|
} else {
|
|
|
|
|
Ok(t)
|
|
|
|
|
}
|
2025-12-05 19:09:06 -05:00
|
|
|
},
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get filled order options
|
|
|
|
|
async fn get_filled_order_options(
|
|
|
|
|
&self,
|
|
|
|
|
token_id: &str,
|
|
|
|
|
options: Option<&OrderOptions>,
|
|
|
|
|
) -> Result<OrderOptions> {
|
|
|
|
|
let (tick_size, neg_risk, fee_rate_bps) = match options {
|
|
|
|
|
Some(o) => (o.tick_size, o.neg_risk, o.fee_rate_bps),
|
|
|
|
|
None => (None, None, None),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let tick_size = self.resolve_tick_size(token_id, tick_size).await?;
|
|
|
|
|
let neg_risk = match neg_risk {
|
|
|
|
|
Some(nr) => nr,
|
|
|
|
|
None => self.get_neg_risk(token_id).await?,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Ok(OrderOptions {
|
|
|
|
|
tick_size: Some(tick_size),
|
|
|
|
|
neg_risk: Some(neg_risk),
|
|
|
|
|
fee_rate_bps,
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check if price is in valid range
|
|
|
|
|
fn is_price_in_range(&self, price: Decimal, tick_size: Decimal) -> bool {
|
|
|
|
|
let min_price = tick_size;
|
|
|
|
|
let max_price = Decimal::ONE - tick_size;
|
|
|
|
|
price >= min_price && price <= max_price
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create an order
|
|
|
|
|
pub async fn create_order(
|
|
|
|
|
&self,
|
|
|
|
|
order_args: &OrderArgs,
|
|
|
|
|
expiration: Option<u64>,
|
|
|
|
|
extras: Option<crate::types::ExtraOrderArgs>,
|
|
|
|
|
options: Option<&OrderOptions>,
|
|
|
|
|
) -> Result<SignedOrderRequest> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let order_builder = self
|
|
|
|
|
.order_builder
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Order builder not initialized"))?;
|
|
|
|
|
|
|
|
|
|
let create_order_options = self
|
|
|
|
|
.get_filled_order_options(&order_args.token_id, options)
|
|
|
|
|
.await?;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
let expiration = expiration.unwrap_or(0);
|
|
|
|
|
let extras = extras.unwrap_or_default();
|
|
|
|
|
|
|
|
|
|
if !self.is_price_in_range(
|
|
|
|
|
order_args.price,
|
|
|
|
|
create_order_options.tick_size.expect("Should be filled"),
|
|
|
|
|
) {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::validation(
|
|
|
|
|
"Price is not in range of tick_size",
|
|
|
|
|
));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
order_builder.create_order(
|
|
|
|
|
self.chain_id,
|
|
|
|
|
order_args,
|
|
|
|
|
expiration,
|
|
|
|
|
&extras,
|
|
|
|
|
&create_order_options,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Calculate market price from order book
|
|
|
|
|
async fn calculate_market_price(
|
|
|
|
|
&self,
|
|
|
|
|
token_id: &str,
|
|
|
|
|
side: Side,
|
|
|
|
|
amount: Decimal,
|
|
|
|
|
) -> Result<Decimal> {
|
|
|
|
|
let book = self.get_order_book(token_id).await?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let order_builder = self
|
|
|
|
|
.order_builder
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Order builder not initialized"))?;
|
|
|
|
|
|
|
|
|
|
// Convert OrderSummary to BookLevel
|
|
|
|
|
let levels: Vec<crate::types::BookLevel> = match side {
|
2025-12-05 19:09:06 -05:00
|
|
|
Side::BUY => book
|
|
|
|
|
.asks
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|s| crate::types::BookLevel {
|
|
|
|
|
price: s.price,
|
|
|
|
|
size: s.size,
|
|
|
|
|
})
|
|
|
|
|
.collect(),
|
|
|
|
|
Side::SELL => book
|
|
|
|
|
.bids
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|s| crate::types::BookLevel {
|
|
|
|
|
price: s.price,
|
|
|
|
|
size: s.size,
|
|
|
|
|
})
|
|
|
|
|
.collect(),
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
order_builder.calculate_market_price(&levels, amount)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create a market order
|
|
|
|
|
pub async fn create_market_order(
|
|
|
|
|
&self,
|
|
|
|
|
order_args: &crate::types::MarketOrderArgs,
|
|
|
|
|
extras: Option<crate::types::ExtraOrderArgs>,
|
|
|
|
|
options: Option<&OrderOptions>,
|
|
|
|
|
) -> Result<SignedOrderRequest> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let order_builder = self
|
|
|
|
|
.order_builder
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Order builder not initialized"))?;
|
|
|
|
|
|
|
|
|
|
let create_order_options = self
|
|
|
|
|
.get_filled_order_options(&order_args.token_id, options)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
let extras = extras.unwrap_or_default();
|
|
|
|
|
let price = self
|
|
|
|
|
.calculate_market_price(&order_args.token_id, Side::BUY, order_args.amount)
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !self.is_price_in_range(
|
|
|
|
|
price,
|
|
|
|
|
create_order_options.tick_size.expect("Should be filled"),
|
|
|
|
|
) {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::validation(
|
|
|
|
|
"Price is not in range of tick_size",
|
|
|
|
|
));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
order_builder.create_market_order(
|
|
|
|
|
self.chain_id,
|
|
|
|
|
order_args,
|
|
|
|
|
price,
|
|
|
|
|
&extras,
|
|
|
|
|
&create_order_options,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Post an order to the exchange
|
|
|
|
|
pub async fn post_order(
|
|
|
|
|
&self,
|
|
|
|
|
order: SignedOrderRequest,
|
|
|
|
|
order_type: OrderType,
|
|
|
|
|
) -> Result<Value> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("API credentials not set"))?;
|
|
|
|
|
|
2025-12-16 22:17:24 -05:00
|
|
|
// Owner field must reference the credential principal identifier
|
|
|
|
|
// to maintain consistency with the authentication context layer
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
let body = PostOrder::new(order, api_creds.api_key.clone(), order_type);
|
|
|
|
|
|
|
|
|
|
let headers = create_l2_headers(signer, api_creds, "POST", "/order", Some(&body))?;
|
|
|
|
|
let req = self.create_request_with_headers(Method::POST, "/order", headers.into_iter());
|
|
|
|
|
|
|
|
|
|
let response = req.json(&body).send().await?;
|
|
|
|
|
if !response.status().is_success() {
|
2026-01-30 21:10:03 -05:00
|
|
|
let status = response.status().as_u16();
|
|
|
|
|
let body = response.text().await.unwrap_or_default();
|
|
|
|
|
let message = if body.is_empty() {
|
|
|
|
|
"Failed to post order".to_string()
|
|
|
|
|
} else {
|
|
|
|
|
format!("Failed to post order: {}", body)
|
|
|
|
|
};
|
|
|
|
|
return Err(PolyfillError::api(status, message));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Cancel an order
|
|
|
|
|
pub async fn cancel(&self, order_id: &str) -> Result<Value> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("API credentials not set"))?;
|
|
|
|
|
|
|
|
|
|
let body = std::collections::HashMap::from([("orderID", order_id)]);
|
|
|
|
|
|
|
|
|
|
let headers = create_l2_headers(signer, api_creds, "DELETE", "/order", Some(&body))?;
|
|
|
|
|
let req = self.create_request_with_headers(Method::DELETE, "/order", headers.into_iter());
|
|
|
|
|
|
|
|
|
|
let response = req.json(&body).send().await?;
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to cancel order",
|
|
|
|
|
));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(response.json::<Value>().await?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Cancel multiple orders
|
|
|
|
|
pub async fn cancel_orders(&self, order_ids: &[String]) -> Result<Value> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("API credentials not set"))?;
|
|
|
|
|
|
|
|
|
|
let headers = create_l2_headers(signer, api_creds, "DELETE", "/orders", Some(order_ids))?;
|
|
|
|
|
let req = self.create_request_with_headers(Method::DELETE, "/orders", headers.into_iter());
|
|
|
|
|
|
|
|
|
|
let response = req.json(order_ids).send().await?;
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to cancel orders",
|
|
|
|
|
));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(response.json::<Value>().await?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Cancel all orders
|
|
|
|
|
pub async fn cancel_all(&self) -> Result<Value> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("API credentials not set"))?;
|
|
|
|
|
|
|
|
|
|
let headers = create_l2_headers::<Value>(signer, api_creds, "DELETE", "/cancel-all", None)?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let req =
|
|
|
|
|
self.create_request_with_headers(Method::DELETE, "/cancel-all", headers.into_iter());
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
|
|
|
|
|
let response = req.send().await?;
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to cancel all orders",
|
|
|
|
|
));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(response.json::<Value>().await?)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get open orders with optional filtering
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// This retrieves all open orders for the authenticated user. You can filter by:
|
|
|
|
|
/// - Order ID (exact match)
|
|
|
|
|
/// - Asset/Token ID (all orders for a specific token)
|
|
|
|
|
/// - Market ID (all orders for a specific market)
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// The response includes order status, fill information, and timestamps.
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_orders(
|
|
|
|
|
&self,
|
|
|
|
|
params: Option<&crate::types::OpenOrderParams>,
|
|
|
|
|
next_cursor: Option<&str>,
|
|
|
|
|
) -> Result<Vec<crate::types::OpenOrder>> {
|
|
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("API credentials not set"))?;
|
|
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let method = Method::GET;
|
|
|
|
|
let endpoint = "/data/orders";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let query_params = match params {
|
|
|
|
|
None => Vec::new(),
|
|
|
|
|
Some(p) => p.to_query_params(),
|
|
|
|
|
};
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let mut next_cursor = next_cursor.unwrap_or("MA==").to_string(); // INITIAL_CURSOR
|
|
|
|
|
let mut output = Vec::new();
|
2025-12-05 19:09:06 -05:00
|
|
|
|
|
|
|
|
while next_cursor != "LTE=" {
|
|
|
|
|
// END_CURSOR
|
|
|
|
|
let req = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method.clone(), format!("{}{}", self.base_url, endpoint))
|
|
|
|
|
.query(&query_params)
|
|
|
|
|
.query(&[("next_cursor", &next_cursor)]);
|
|
|
|
|
|
|
|
|
|
let r = headers
|
|
|
|
|
.clone()
|
|
|
|
|
.into_iter()
|
|
|
|
|
.fold(req, |r, (k, v)| r.header(HeaderName::from_static(k), v));
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let resp = r
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?
|
2025-12-05 19:09:06 -05:00
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| {
|
|
|
|
|
PolyfillError::parse(format!("Failed to parse response: {}", e), None)
|
|
|
|
|
})?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
|
|
|
|
let new_cursor = resp["next_cursor"]
|
|
|
|
|
.as_str()
|
2025-12-05 19:09:06 -05:00
|
|
|
.ok_or_else(|| {
|
|
|
|
|
PolyfillError::parse("Failed to parse next cursor".to_string(), None)
|
|
|
|
|
})?
|
2025-11-04 21:59:40 -05:00
|
|
|
.to_owned();
|
|
|
|
|
|
|
|
|
|
next_cursor = new_cursor;
|
|
|
|
|
|
|
|
|
|
let results = resp["data"].clone();
|
2025-12-05 19:09:06 -05:00
|
|
|
let orders =
|
|
|
|
|
serde_json::from_value::<Vec<crate::types::OpenOrder>>(results).map_err(|e| {
|
|
|
|
|
PolyfillError::parse(
|
|
|
|
|
format!("Failed to parse data from order response: {}", e),
|
|
|
|
|
None,
|
|
|
|
|
)
|
|
|
|
|
})?;
|
2025-11-04 21:59:40 -05:00
|
|
|
output.extend(orders);
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
Ok(output)
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get trade history with optional filtering
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// This retrieves historical trades for the authenticated user. You can filter by:
|
|
|
|
|
/// - Trade ID (exact match)
|
|
|
|
|
/// - Maker address (trades where you were the maker)
|
|
|
|
|
/// - Market ID (trades in a specific market)
|
|
|
|
|
/// - Asset/Token ID (trades for a specific token)
|
|
|
|
|
/// - Time range (before/after timestamps)
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// Trades are returned in reverse chronological order (newest first).
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_trades(
|
|
|
|
|
&self,
|
|
|
|
|
trade_params: Option<&crate::types::TradeParams>,
|
|
|
|
|
next_cursor: Option<&str>,
|
|
|
|
|
) -> Result<Vec<Value>> {
|
|
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("API credentials not set"))?;
|
|
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let method = Method::GET;
|
|
|
|
|
let endpoint = "/data/trades";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let query_params = match trade_params {
|
|
|
|
|
None => Vec::new(),
|
|
|
|
|
Some(p) => p.to_query_params(),
|
|
|
|
|
};
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let mut next_cursor = next_cursor.unwrap_or("MA==").to_string(); // INITIAL_CURSOR
|
|
|
|
|
let mut output = Vec::new();
|
2025-12-05 19:09:06 -05:00
|
|
|
|
|
|
|
|
while next_cursor != "LTE=" {
|
|
|
|
|
// END_CURSOR
|
|
|
|
|
let req = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method.clone(), format!("{}{}", self.base_url, endpoint))
|
|
|
|
|
.query(&query_params)
|
|
|
|
|
.query(&[("next_cursor", &next_cursor)]);
|
|
|
|
|
|
|
|
|
|
let r = headers
|
|
|
|
|
.clone()
|
|
|
|
|
.into_iter()
|
|
|
|
|
.fold(req, |r, (k, v)| r.header(HeaderName::from_static(k), v));
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let resp = r
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?
|
2025-12-05 19:09:06 -05:00
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
|
|
|
|
.map_err(|e| {
|
|
|
|
|
PolyfillError::parse(format!("Failed to parse response: {}", e), None)
|
|
|
|
|
})?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
|
|
|
|
let new_cursor = resp["next_cursor"]
|
|
|
|
|
.as_str()
|
2025-12-05 19:09:06 -05:00
|
|
|
.ok_or_else(|| {
|
|
|
|
|
PolyfillError::parse("Failed to parse next cursor".to_string(), None)
|
|
|
|
|
})?
|
2025-11-04 21:59:40 -05:00
|
|
|
.to_owned();
|
|
|
|
|
|
|
|
|
|
next_cursor = new_cursor;
|
|
|
|
|
|
|
|
|
|
let results = resp["data"].clone();
|
|
|
|
|
output.push(results);
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
Ok(output)
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get balance and allowance information for all assets
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// This returns the current balance and allowance for each asset in your account.
|
|
|
|
|
/// Balance is how much you own, allowance is how much the exchange can spend on your behalf.
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// You need both balance and allowance to place orders - the exchange needs permission
|
|
|
|
|
/// to move your tokens when orders are filled.
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_balance_allowance(
|
|
|
|
|
&self,
|
|
|
|
|
params: Option<crate::types::BalanceAllowanceParams>,
|
|
|
|
|
) -> Result<Value> {
|
|
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("API credentials not set"))?;
|
|
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let mut params = params.unwrap_or_default();
|
|
|
|
|
if params.signature_type.is_none() {
|
|
|
|
|
params.set_signature_type(
|
|
|
|
|
self.order_builder
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("OrderBuilder not set")
|
|
|
|
|
.get_sig_type(),
|
|
|
|
|
);
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let query_params = params.to_query_params();
|
|
|
|
|
|
|
|
|
|
let method = Method::GET;
|
|
|
|
|
let endpoint = "/balance-allowance";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&query_params)
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Set up notifications for order fills and other events
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// This configures push notifications so you get alerted when:
|
|
|
|
|
/// - Your orders get filled
|
|
|
|
|
/// - Your orders get cancelled
|
|
|
|
|
/// - Market conditions change significantly
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// The signature proves you own the account and want to receive notifications.
|
2025-11-04 21:59:40 -05:00
|
|
|
pub async fn get_notifications(&self) -> Result<Value> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("Signer not set"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.ok_or_else(|| PolyfillError::auth("API credentials not set"))?;
|
|
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let method = Method::GET;
|
|
|
|
|
let endpoint = "/notifications";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&[(
|
|
|
|
|
"signature_type",
|
|
|
|
|
&self
|
|
|
|
|
.order_builder
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("OrderBuilder not set")
|
2025-12-05 19:09:06 -05:00
|
|
|
.get_sig_type()
|
|
|
|
|
.to_string(),
|
2025-11-04 21:59:40 -05:00
|
|
|
)])
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get midpoints for multiple tokens in a single request
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// This is much more efficient than calling get_midpoint() multiple times.
|
|
|
|
|
/// Instead of N round trips, you make just 1 request and get all the midpoints back.
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// Midpoints are returned as a HashMap where the key is the token_id and the value
|
|
|
|
|
/// is the midpoint price (or None if there's no valid midpoint).
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_midpoints(
|
|
|
|
|
&self,
|
|
|
|
|
token_ids: &[String],
|
|
|
|
|
) -> Result<std::collections::HashMap<String, Decimal>> {
|
2025-11-04 21:59:40 -05:00
|
|
|
let request_data: Vec<std::collections::HashMap<&str, String>> = token_ids
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|id| {
|
|
|
|
|
let mut map = std::collections::HashMap::new();
|
|
|
|
|
map.insert("token_id", id.clone());
|
|
|
|
|
map
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
2025-12-05 19:09:06 -05:00
|
|
|
|
|
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.post(format!("{}/midpoints", self.base_url))
|
2025-11-04 21:59:40 -05:00
|
|
|
.json(&request_data)
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get batch midpoints",
|
|
|
|
|
));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
2025-11-04 21:59:40 -05:00
|
|
|
let midpoints: std::collections::HashMap<String, Decimal> = response.json().await?;
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
Ok(midpoints)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get bid/ask/mid prices for multiple tokens in a single request
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// This gives you the full price picture for multiple tokens at once.
|
|
|
|
|
/// Much more efficient than individual calls, especially when you're tracking
|
|
|
|
|
/// a portfolio or comparing multiple markets.
|
2025-12-05 19:09:06 -05:00
|
|
|
///
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
/// Returns bid (best buy price), ask (best sell price), and mid (average) for each token.
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_prices(
|
|
|
|
|
&self,
|
|
|
|
|
book_params: &[crate::types::BookParams],
|
|
|
|
|
) -> Result<std::collections::HashMap<String, std::collections::HashMap<Side, Decimal>>> {
|
2025-11-04 21:59:40 -05:00
|
|
|
let request_data: Vec<std::collections::HashMap<&str, String>> = book_params
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|params| {
|
|
|
|
|
let mut map = std::collections::HashMap::new();
|
|
|
|
|
map.insert("token_id", params.token_id.clone());
|
|
|
|
|
map.insert("side", params.side.as_str().to_string());
|
|
|
|
|
map
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
2025-12-05 19:09:06 -05:00
|
|
|
|
|
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.post(format!("{}/prices", self.base_url))
|
2025-11-04 21:59:40 -05:00
|
|
|
.json(&request_data)
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
.send()
|
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
|
|
if !response.status().is_success() {
|
2025-12-05 19:09:06 -05:00
|
|
|
return Err(PolyfillError::api(
|
|
|
|
|
response.status().as_u16(),
|
|
|
|
|
"Failed to get batch prices",
|
|
|
|
|
));
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
}
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let prices: std::collections::HashMap<String, std::collections::HashMap<Side, Decimal>> =
|
|
|
|
|
response.json().await?;
|
feat: Add EIP-712 signing for L1 authentication (src/auth.rs), HMAC-SHA256 for L2 API authentication, create_api_key(), derive_api_key(), create_or_derive_api_key(), Add set_api_creds() for credential management, Add create_order() and create_market_order() with EIP-712 signing, Add post_order() and create_and_post_order() for order submission, Add cancel(), cancel_orders(), cancel_all() for order management, Add OrderBuilder with proper tick size validation and rounding, Add get_orders() with filtering by ID, asset, market, Add get_trades() with filtering by time range, maker, asset, Add OpenOrderParams and TradeParams for query flexibility, Add balance_allowance() for balance and allowance queries, Add notifications() for push notification setup, Add get_midpoints() for efficient multi-token midpoint queries, Add get_prices() for batch bid/ask/mid price retrieval, Add BatchMidpointRequest/Response and BatchPriceRequest/Response types, Replace Decimal with u32 (Price) and i64 (Qty) on hot paths, Add decimal_to_price() and decimal_to_qty() conversion functions
2025-10-20 18:31:22 -04:00
|
|
|
Ok(prices)
|
|
|
|
|
}
|
2025-11-04 21:59:40 -05:00
|
|
|
|
|
|
|
|
/// Get order book for multiple tokens (batch) - reference implementation compatible
|
|
|
|
|
pub async fn get_order_books(&self, token_ids: &[String]) -> Result<Vec<OrderBookSummary>> {
|
|
|
|
|
let request_data: Vec<std::collections::HashMap<&str, String>> = token_ids
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|id| {
|
|
|
|
|
let mut map = std::collections::HashMap::new();
|
|
|
|
|
map.insert("token_id", id.clone());
|
|
|
|
|
map
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.post(format!("{}/books", self.base_url))
|
2025-11-04 21:59:40 -05:00
|
|
|
.json(&request_data)
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<Vec<OrderBookSummary>>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get single order by ID
|
|
|
|
|
pub async fn get_order(&self, order_id: &str) -> Result<crate::types::OpenOrder> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("Signer not configured"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("API credentials not configured"))?;
|
|
|
|
|
|
|
|
|
|
let method = Method::GET;
|
|
|
|
|
let endpoint = &format!("/data/order/{}", order_id);
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 21:59:40 -05:00
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<crate::types::OpenOrder>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get last trade price for a token
|
|
|
|
|
pub async fn get_last_trade_price(&self, token_id: &str) -> Result<Value> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/last-trade-price", self.base_url))
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&[("token_id", token_id)])
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get last trade prices for multiple tokens
|
|
|
|
|
pub async fn get_last_trade_prices(&self, token_ids: &[String]) -> Result<Value> {
|
|
|
|
|
let request_data: Vec<std::collections::HashMap<&str, String>> = token_ids
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|id| {
|
|
|
|
|
let mut map = std::collections::HashMap::new();
|
|
|
|
|
map.insert("token_id", id.clone());
|
|
|
|
|
map
|
|
|
|
|
})
|
|
|
|
|
.collect();
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.post(format!("{}/last-trades-prices", self.base_url))
|
2025-11-04 21:59:40 -05:00
|
|
|
.json(&request_data)
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Cancel market orders with optional filters
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn cancel_market_orders(
|
|
|
|
|
&self,
|
|
|
|
|
market: Option<&str>,
|
|
|
|
|
asset_id: Option<&str>,
|
|
|
|
|
) -> Result<Value> {
|
|
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("Signer not configured"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("API credentials not configured"))?;
|
|
|
|
|
|
|
|
|
|
let method = Method::DELETE;
|
|
|
|
|
let endpoint = "/cancel-market-orders";
|
|
|
|
|
let body = std::collections::HashMap::from([
|
|
|
|
|
("market", market.unwrap_or("")),
|
|
|
|
|
("asset_id", asset_id.unwrap_or("")),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
let headers = create_l2_headers(signer, api_creds, method.as_str(), endpoint, Some(&body))?;
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 21:59:40 -05:00
|
|
|
.json(&body)
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Drop (delete) notifications by IDs
|
|
|
|
|
pub async fn drop_notifications(&self, ids: &[String]) -> Result<Value> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("Signer not configured"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("API credentials not configured"))?;
|
|
|
|
|
|
|
|
|
|
let method = Method::DELETE;
|
|
|
|
|
let endpoint = "/notifications";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&[("ids", ids.join(","))])
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Update balance allowance
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn update_balance_allowance(
|
|
|
|
|
&self,
|
|
|
|
|
params: Option<crate::types::BalanceAllowanceParams>,
|
|
|
|
|
) -> Result<Value> {
|
|
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("Signer not configured"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("API credentials not configured"))?;
|
|
|
|
|
|
|
|
|
|
let mut params = params.unwrap_or_default();
|
|
|
|
|
if params.signature_type.is_none() {
|
|
|
|
|
params.set_signature_type(
|
|
|
|
|
self.order_builder
|
|
|
|
|
.as_ref()
|
|
|
|
|
.expect("OrderBuilder not set")
|
|
|
|
|
.get_sig_type(),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let query_params = params.to_query_params();
|
|
|
|
|
|
|
|
|
|
let method = Method::GET;
|
|
|
|
|
let endpoint = "/balance-allowance/update";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&query_params)
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check if an order is scoring
|
|
|
|
|
pub async fn is_order_scoring(&self, order_id: &str) -> Result<bool> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("Signer not configured"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("API credentials not configured"))?;
|
|
|
|
|
|
|
|
|
|
let method = Method::GET;
|
|
|
|
|
let endpoint = "/order-scoring";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers =
|
|
|
|
|
create_l2_headers::<Value>(signer, api_creds, method.as_str(), endpoint, None)?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&[("order_id", order_id)])
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let result: Value = response
|
|
|
|
|
.json()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))?;
|
|
|
|
|
|
|
|
|
|
Ok(result["scoring"].as_bool().unwrap_or(false))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Check if multiple orders are scoring
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn are_orders_scoring(
|
|
|
|
|
&self,
|
|
|
|
|
order_ids: &[&str],
|
|
|
|
|
) -> Result<std::collections::HashMap<String, bool>> {
|
|
|
|
|
let signer = self
|
|
|
|
|
.signer
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("Signer not configured"))?;
|
2025-12-05 19:09:06 -05:00
|
|
|
let api_creds = self
|
|
|
|
|
.api_creds
|
|
|
|
|
.as_ref()
|
2025-11-04 21:59:40 -05:00
|
|
|
.ok_or_else(|| PolyfillError::config("API credentials not configured"))?;
|
|
|
|
|
|
|
|
|
|
let method = Method::POST;
|
|
|
|
|
let endpoint = "/orders-scoring";
|
2025-12-05 19:09:06 -05:00
|
|
|
let headers = create_l2_headers(
|
|
|
|
|
signer,
|
|
|
|
|
api_creds,
|
|
|
|
|
method.as_str(),
|
|
|
|
|
endpoint,
|
|
|
|
|
Some(order_ids),
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-11-04 21:59:40 -05:00
|
|
|
.request(method, format!("{}{}", self.base_url, endpoint))
|
2025-12-05 19:09:06 -05:00
|
|
|
.headers(
|
|
|
|
|
headers
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|(k, v)| (HeaderName::from_static(k), v.parse().unwrap()))
|
|
|
|
|
.collect(),
|
|
|
|
|
)
|
2025-11-04 21:59:40 -05:00
|
|
|
.json(order_ids)
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<std::collections::HashMap<String, bool>>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get sampling markets with pagination
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_sampling_markets(
|
|
|
|
|
&self,
|
|
|
|
|
next_cursor: Option<&str>,
|
|
|
|
|
) -> Result<crate::types::MarketsResponse> {
|
2025-11-04 21:59:40 -05:00
|
|
|
let next_cursor = next_cursor.unwrap_or("MA=="); // INITIAL_CURSOR
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/sampling-markets", self.base_url))
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&[("next_cursor", next_cursor)])
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<crate::types::MarketsResponse>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get sampling simplified markets with pagination
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_sampling_simplified_markets(
|
|
|
|
|
&self,
|
|
|
|
|
next_cursor: Option<&str>,
|
|
|
|
|
) -> Result<crate::types::SimplifiedMarketsResponse> {
|
2025-11-04 21:59:40 -05:00
|
|
|
let next_cursor = next_cursor.unwrap_or("MA=="); // INITIAL_CURSOR
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/sampling-simplified-markets", self.base_url))
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&[("next_cursor", next_cursor)])
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<crate::types::SimplifiedMarketsResponse>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get markets with pagination
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_markets(
|
|
|
|
|
&self,
|
|
|
|
|
next_cursor: Option<&str>,
|
|
|
|
|
) -> Result<crate::types::MarketsResponse> {
|
2025-11-04 21:59:40 -05:00
|
|
|
let next_cursor = next_cursor.unwrap_or("MA=="); // INITIAL_CURSOR
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/markets", self.base_url))
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&[("next_cursor", next_cursor)])
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<crate::types::MarketsResponse>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get simplified markets with pagination
|
2025-12-05 19:09:06 -05:00
|
|
|
pub async fn get_simplified_markets(
|
|
|
|
|
&self,
|
|
|
|
|
next_cursor: Option<&str>,
|
|
|
|
|
) -> Result<crate::types::SimplifiedMarketsResponse> {
|
2025-11-04 21:59:40 -05:00
|
|
|
let next_cursor = next_cursor.unwrap_or("MA=="); // INITIAL_CURSOR
|
|
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/simplified-markets", self.base_url))
|
2025-11-04 21:59:40 -05:00
|
|
|
.query(&[("next_cursor", next_cursor)])
|
|
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<crate::types::SimplifiedMarketsResponse>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get single market by condition ID
|
|
|
|
|
pub async fn get_market(&self, condition_id: &str) -> Result<crate::types::Market> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
2025-12-04 07:37:40 -05:00
|
|
|
.get(format!("{}/markets/{}", self.base_url, condition_id))
|
2025-11-04 21:59:40 -05:00
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<crate::types::Market>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get market trades events
|
|
|
|
|
pub async fn get_market_trades_events(&self, condition_id: &str) -> Result<Value> {
|
2025-12-05 19:09:06 -05:00
|
|
|
let response = self
|
|
|
|
|
.http_client
|
|
|
|
|
.get(format!(
|
|
|
|
|
"{}/live-activity/events/{}",
|
|
|
|
|
self.base_url, condition_id
|
|
|
|
|
))
|
2025-11-04 21:59:40 -05:00
|
|
|
.send()
|
|
|
|
|
.await
|
2025-11-04 22:59:20 -05:00
|
|
|
.map_err(|e| PolyfillError::network(format!("Request failed: {}", e), e))?;
|
2025-11-04 21:59:40 -05:00
|
|
|
|
2025-12-05 19:09:06 -05:00
|
|
|
response
|
|
|
|
|
.json::<Value>()
|
|
|
|
|
.await
|
2025-11-04 21:59:40 -05:00
|
|
|
.map_err(|e| PolyfillError::parse(format!("Failed to parse response: {}", e), None))
|
|
|
|
|
}
|
2025-07-24 20:29:10 -04:00
|
|
|
}
|
|
|
|
|
|
2025-11-04 22:57:43 -05:00
|
|
|
// Re-export types from the canonical location in types.rs
|
|
|
|
|
pub use crate::types::{
|
2025-12-05 19:09:06 -05:00
|
|
|
ExtraOrderArgs, Market, MarketOrderArgs, MarketsResponse, MidpointResponse, NegRiskResponse,
|
2026-01-31 10:30:48 -05:00
|
|
|
OrderBookSummary, OrderSummary, PriceResponse, PricesHistoryInterval, PricesHistoryResponse,
|
|
|
|
|
Rewards, SpreadResponse, TickSizeResponse, Token,
|
2025-11-04 22:57:43 -05:00
|
|
|
};
|
2025-07-24 20:29:10 -04:00
|
|
|
|
2025-11-04 22:57:43 -05:00
|
|
|
// Compatibility types that need to stay in client.rs
|
2025-07-24 20:29:10 -04:00
|
|
|
#[derive(Debug, Default)]
|
|
|
|
|
pub struct CreateOrderOptions {
|
|
|
|
|
pub tick_size: Option<Decimal>,
|
|
|
|
|
pub neg_risk: Option<bool>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Re-export for compatibility
|
2025-11-04 23:26:07 -05:00
|
|
|
pub type PolyfillClient = ClobClient;
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
2025-12-04 06:59:20 -05:00
|
|
|
use super::{ClobClient, OrderArgs as ClientOrderArgs};
|
2026-01-31 10:30:48 -05:00
|
|
|
use crate::types::{PricesHistoryInterval, Side};
|
2025-12-04 06:59:20 -05:00
|
|
|
use crate::{ApiCredentials, PolyfillError};
|
2025-11-04 23:26:07 -05:00
|
|
|
use mockito::{Matcher, Server};
|
|
|
|
|
use rust_decimal::Decimal;
|
|
|
|
|
use std::str::FromStr;
|
|
|
|
|
use tokio;
|
|
|
|
|
|
|
|
|
|
fn create_test_client(base_url: &str) -> ClobClient {
|
|
|
|
|
ClobClient::new(base_url)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn create_test_client_with_auth(base_url: &str) -> ClobClient {
|
|
|
|
|
ClobClient::with_l1_headers(
|
|
|
|
|
base_url,
|
|
|
|
|
"0x1234567890123456789012345678901234567890123456789012345678901234",
|
|
|
|
|
137,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_client_creation() {
|
|
|
|
|
let client = create_test_client("https://test.example.com");
|
|
|
|
|
assert_eq!(client.base_url, "https://test.example.com");
|
|
|
|
|
assert!(client.signer.is_none());
|
|
|
|
|
assert!(client.api_creds.is_none());
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_client_with_l1_headers() {
|
|
|
|
|
let client = create_test_client_with_auth("https://test.example.com");
|
|
|
|
|
assert_eq!(client.base_url, "https://test.example.com");
|
|
|
|
|
assert!(client.signer.is_some());
|
|
|
|
|
assert_eq!(client.chain_id, 137);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_client_with_l2_headers() {
|
2025-11-04 23:26:29 -05:00
|
|
|
let api_creds = ApiCredentials {
|
|
|
|
|
api_key: "test_key".to_string(),
|
2025-11-04 23:26:07 -05:00
|
|
|
secret: "test_secret".to_string(),
|
|
|
|
|
passphrase: "test_passphrase".to_string(),
|
|
|
|
|
};
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
let client = ClobClient::with_l2_headers(
|
|
|
|
|
"https://test.example.com",
|
|
|
|
|
"0x1234567890123456789012345678901234567890123456789012345678901234",
|
|
|
|
|
137,
|
|
|
|
|
api_creds.clone(),
|
|
|
|
|
);
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
assert_eq!(client.base_url, "https://test.example.com");
|
|
|
|
|
assert!(client.signer.is_some());
|
|
|
|
|
assert!(client.api_creds.is_some());
|
|
|
|
|
assert_eq!(client.chain_id, 137);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_set_api_creds() {
|
|
|
|
|
let mut client = create_test_client("https://test.example.com");
|
|
|
|
|
assert!(client.api_creds.is_none());
|
|
|
|
|
|
2025-11-04 23:26:29 -05:00
|
|
|
let api_creds = ApiCredentials {
|
|
|
|
|
api_key: "test_key".to_string(),
|
2025-11-04 23:26:07 -05:00
|
|
|
secret: "test_secret".to_string(),
|
|
|
|
|
passphrase: "test_passphrase".to_string(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
client.set_api_creds(api_creds.clone());
|
|
|
|
|
assert!(client.api_creds.is_some());
|
2025-11-04 23:26:29 -05:00
|
|
|
assert_eq!(client.api_creds.unwrap().api_key, "test_key");
|
2025-11-04 23:26:07 -05:00
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_get_sampling_markets_success() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
2026-01-01 15:04:32 -05:00
|
|
|
"limit": 10,
|
|
|
|
|
"count": 2,
|
2025-11-04 23:26:07 -05:00
|
|
|
"next_cursor": null,
|
|
|
|
|
"data": [
|
|
|
|
|
{
|
|
|
|
|
"condition_id": "0x123",
|
|
|
|
|
"tokens": [
|
2026-01-01 15:04:32 -05:00
|
|
|
{"token_id": "0x456", "outcome": "Yes", "price": 0.5, "winner": false},
|
|
|
|
|
{"token_id": "0x789", "outcome": "No", "price": 0.5, "winner": false}
|
2025-11-04 23:26:07 -05:00
|
|
|
],
|
|
|
|
|
"rewards": {
|
|
|
|
|
"rates": null,
|
2026-01-01 15:04:32 -05:00
|
|
|
"min_size": 1.0,
|
|
|
|
|
"max_spread": 0.1,
|
2025-11-04 23:26:07 -05:00
|
|
|
"event_start_date": null,
|
|
|
|
|
"event_end_date": null,
|
|
|
|
|
"in_game_multiplier": null,
|
|
|
|
|
"reward_epoch": null
|
|
|
|
|
},
|
|
|
|
|
"min_incentive_size": null,
|
|
|
|
|
"max_incentive_spread": null,
|
|
|
|
|
"active": true,
|
|
|
|
|
"closed": false,
|
|
|
|
|
"question_id": "0x123",
|
2026-01-01 15:04:32 -05:00
|
|
|
"minimum_order_size": 1.0,
|
|
|
|
|
"minimum_tick_size": 0.01,
|
2025-11-04 23:26:07 -05:00
|
|
|
"description": "Test market",
|
|
|
|
|
"category": "test",
|
|
|
|
|
"end_date_iso": null,
|
|
|
|
|
"game_start_time": null,
|
|
|
|
|
"question": "Will this test pass?",
|
|
|
|
|
"market_slug": "test-market",
|
2026-01-01 15:04:32 -05:00
|
|
|
"seconds_delay": 0,
|
2025-11-04 23:26:07 -05:00
|
|
|
"icon": "",
|
|
|
|
|
"fpmm": ""
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/sampling-markets")
|
2025-11-05 20:28:51 -05:00
|
|
|
.match_query(Matcher::UrlEncoded("next_cursor".into(), "MA==".into()))
|
2025-11-04 23:26:07 -05:00
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_sampling_markets(None).await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let markets = result.unwrap();
|
|
|
|
|
assert_eq!(markets.data.len(), 1);
|
|
|
|
|
assert_eq!(markets.data[0].question, "Will this test pass?");
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_get_sampling_markets_with_cursor() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
2026-01-01 15:04:32 -05:00
|
|
|
"limit": 5,
|
|
|
|
|
"count": 0,
|
2025-11-04 23:26:07 -05:00
|
|
|
"next_cursor": null,
|
|
|
|
|
"data": []
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/sampling-markets")
|
2025-12-05 19:09:06 -05:00
|
|
|
.match_query(Matcher::AllOf(vec![Matcher::UrlEncoded(
|
|
|
|
|
"next_cursor".into(),
|
|
|
|
|
"test_cursor".into(),
|
|
|
|
|
)]))
|
2025-11-04 23:26:07 -05:00
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_sampling_markets(Some("test_cursor")).await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let markets = result.unwrap();
|
|
|
|
|
assert_eq!(markets.data.len(), 0);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_get_order_book_success() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
|
|
|
|
"market": "0x123",
|
2025-11-05 20:28:51 -05:00
|
|
|
"asset_id": "0x123",
|
|
|
|
|
"hash": "0xabc123",
|
|
|
|
|
"timestamp": "1234567890",
|
2025-11-04 23:26:07 -05:00
|
|
|
"bids": [
|
|
|
|
|
{"price": "0.75", "size": "100.0"}
|
|
|
|
|
],
|
|
|
|
|
"asks": [
|
|
|
|
|
{"price": "0.76", "size": "50.0"}
|
2026-01-29 18:33:27 -05:00
|
|
|
],
|
|
|
|
|
"min_order_size": "1",
|
|
|
|
|
"neg_risk": false,
|
|
|
|
|
"tick_size": "0.01",
|
|
|
|
|
"last_trade_price": "0.755"
|
2025-11-04 23:26:07 -05:00
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/book")
|
|
|
|
|
.match_query(Matcher::UrlEncoded("token_id".into(), "0x123".into()))
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_order_book("0x123").await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let book = result.unwrap();
|
|
|
|
|
assert_eq!(book.market, "0x123");
|
|
|
|
|
assert_eq!(book.bids.len(), 1);
|
|
|
|
|
assert_eq!(book.asks.len(), 1);
|
2026-01-29 18:33:27 -05:00
|
|
|
assert_eq!(book.min_order_size, Decimal::from_str("1").unwrap());
|
|
|
|
|
assert!(!book.neg_risk);
|
|
|
|
|
assert_eq!(book.tick_size, Decimal::from_str("0.01").unwrap());
|
2026-01-29 18:47:30 -05:00
|
|
|
assert_eq!(
|
|
|
|
|
book.last_trade_price,
|
|
|
|
|
Some(Decimal::from_str("0.755").unwrap())
|
|
|
|
|
);
|
2025-11-04 23:26:07 -05:00
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_get_midpoint_success() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
|
|
|
|
"mid": "0.755"
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/midpoint")
|
|
|
|
|
.match_query(Matcher::UrlEncoded("token_id".into(), "0x123".into()))
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_midpoint("0x123").await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let response = result.unwrap();
|
|
|
|
|
assert_eq!(response.mid, Decimal::from_str("0.755").unwrap());
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_get_spread_success() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
|
|
|
|
"spread": "0.01"
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/spread")
|
|
|
|
|
.match_query(Matcher::UrlEncoded("token_id".into(), "0x123".into()))
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_spread("0x123").await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let response = result.unwrap();
|
|
|
|
|
assert_eq!(response.spread, Decimal::from_str("0.01").unwrap());
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_get_price_success() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
|
|
|
|
"price": "0.76"
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/price")
|
|
|
|
|
.match_query(Matcher::AllOf(vec![
|
|
|
|
|
Matcher::UrlEncoded("token_id".into(), "0x123".into()),
|
2025-11-04 23:28:21 -05:00
|
|
|
Matcher::UrlEncoded("side".into(), "BUY".into()),
|
2025-11-04 23:26:07 -05:00
|
|
|
]))
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_price("0x123", Side::BUY).await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let response = result.unwrap();
|
|
|
|
|
assert_eq!(response.price, Decimal::from_str("0.76").unwrap());
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 10:30:48 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
|
async fn test_get_prices_history_interval_rejects_hex_condition_id() {
|
|
|
|
|
let client = create_test_client("https://test.example.com");
|
|
|
|
|
let result = client
|
|
|
|
|
.get_prices_history_interval("0xdeadbeef", PricesHistoryInterval::OneDay, None)
|
|
|
|
|
.await;
|
|
|
|
|
assert!(matches!(result, Err(PolyfillError::Validation { .. })));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
|
async fn test_get_prices_history_interval_success() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{"history":[{"t":1}]}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/prices-history")
|
|
|
|
|
.match_query(Matcher::AllOf(vec![
|
|
|
|
|
Matcher::UrlEncoded("market".into(), "12345".into()),
|
|
|
|
|
Matcher::UrlEncoded("interval".into(), "1d".into()),
|
|
|
|
|
Matcher::UrlEncoded("fidelity".into(), "5".into()),
|
|
|
|
|
]))
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let response = client
|
|
|
|
|
.get_prices_history_interval("12345", PricesHistoryInterval::OneDay, Some(5))
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert_eq!(response.history.len(), 1);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_get_tick_size_success() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
|
|
|
|
"minimum_tick_size": "0.01"
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/tick-size")
|
|
|
|
|
.match_query(Matcher::UrlEncoded("token_id".into(), "0x123".into()))
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_tick_size("0x123").await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let tick_size = result.unwrap();
|
|
|
|
|
assert_eq!(tick_size, Decimal::from_str("0.01").unwrap());
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_get_neg_risk_success() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
|
|
|
|
"neg_risk": false
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/neg-risk")
|
|
|
|
|
.match_query(Matcher::UrlEncoded("token_id".into(), "0x123".into()))
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_neg_risk("0x123").await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let neg_risk = result.unwrap();
|
|
|
|
|
assert!(!neg_risk);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_api_error_handling() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/book")
|
2025-12-05 19:09:06 -05:00
|
|
|
.match_query(Matcher::UrlEncoded(
|
|
|
|
|
"token_id".into(),
|
|
|
|
|
"invalid_token".into(),
|
|
|
|
|
))
|
2025-11-04 23:26:07 -05:00
|
|
|
.with_status(404)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(r#"{"error": "Market not found"}"#)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_order_book("invalid_token").await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_err());
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
let error = result.unwrap_err();
|
2025-11-05 20:28:51 -05:00
|
|
|
// The error should be either Network or Api error
|
2025-12-05 19:09:06 -05:00
|
|
|
assert!(
|
|
|
|
|
matches!(error, PolyfillError::Network { .. })
|
|
|
|
|
|| matches!(error, PolyfillError::Api { .. })
|
|
|
|
|
);
|
2025-11-04 23:26:07 -05:00
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_network_error_handling() {
|
|
|
|
|
// Test with invalid URL to simulate network error
|
|
|
|
|
let client = create_test_client("http://invalid-host-that-does-not-exist.com");
|
|
|
|
|
let result = client.get_order_book("0x123").await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
assert!(result.is_err());
|
|
|
|
|
let error = result.unwrap_err();
|
|
|
|
|
assert!(matches!(error, PolyfillError::Network { .. }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2025-11-04 23:26:57 -05:00
|
|
|
fn test_client_url_validation() {
|
2025-11-04 23:26:07 -05:00
|
|
|
let client = create_test_client("https://test.example.com");
|
2025-11-04 23:26:57 -05:00
|
|
|
assert_eq!(client.base_url, "https://test.example.com");
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:57 -05:00
|
|
|
let client2 = create_test_client("http://localhost:8080");
|
|
|
|
|
assert_eq!(client2.base_url, "http://localhost:8080");
|
2025-11-04 23:26:07 -05:00
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-11-04 23:26:07 -05:00
|
|
|
async fn test_get_midpoints_batch() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
|
|
|
|
"0x123": "0.755",
|
|
|
|
|
"0x456": "0.623"
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
2025-11-04 23:28:21 -05:00
|
|
|
.mock("POST", "/midpoints")
|
|
|
|
|
.with_header("content-type", "application/json")
|
2025-11-04 23:26:07 -05:00
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let token_ids = vec!["0x123".to_string(), "0x456".to_string()];
|
|
|
|
|
let result = client.get_midpoints(&token_ids).await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:07 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let midpoints = result.unwrap();
|
|
|
|
|
assert_eq!(midpoints.len(), 2);
|
2025-12-05 19:09:06 -05:00
|
|
|
assert_eq!(
|
|
|
|
|
midpoints.get("0x123").unwrap(),
|
|
|
|
|
&Decimal::from_str("0.755").unwrap()
|
|
|
|
|
);
|
|
|
|
|
assert_eq!(
|
|
|
|
|
midpoints.get("0x456").unwrap(),
|
|
|
|
|
&Decimal::from_str("0.623").unwrap()
|
|
|
|
|
);
|
2025-11-04 23:26:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
2025-11-04 23:26:57 -05:00
|
|
|
fn test_client_configuration() {
|
2025-11-04 23:26:07 -05:00
|
|
|
let client = create_test_client("https://test.example.com");
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:57 -05:00
|
|
|
// Test initial state
|
|
|
|
|
assert!(client.signer.is_none());
|
|
|
|
|
assert!(client.api_creds.is_none());
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-11-04 23:26:57 -05:00
|
|
|
// Test with auth
|
|
|
|
|
let auth_client = create_test_client_with_auth("https://test.example.com");
|
|
|
|
|
assert!(auth_client.signer.is_some());
|
|
|
|
|
assert_eq!(auth_client.chain_id, 137);
|
2025-11-04 23:26:07 -05:00
|
|
|
}
|
2025-12-04 02:28:34 -05:00
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-12-04 02:28:34 -05:00
|
|
|
async fn test_get_ok() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{"status": "ok"}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/ok")
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_ok().await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-12-04 02:28:34 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-12-04 02:28:34 -05:00
|
|
|
async fn test_get_prices_batch() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
|
|
|
|
"0x123": {
|
|
|
|
|
"BUY": "0.755",
|
|
|
|
|
"SELL": "0.745"
|
|
|
|
|
},
|
|
|
|
|
"0x456": {
|
|
|
|
|
"BUY": "0.623",
|
|
|
|
|
"SELL": "0.613"
|
|
|
|
|
}
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("POST", "/prices")
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let book_params = vec![
|
|
|
|
|
crate::types::BookParams {
|
|
|
|
|
token_id: "0x123".to_string(),
|
|
|
|
|
side: Side::BUY,
|
|
|
|
|
},
|
|
|
|
|
crate::types::BookParams {
|
|
|
|
|
token_id: "0x456".to_string(),
|
|
|
|
|
side: Side::SELL,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
let result = client.get_prices(&book_params).await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-12-04 02:28:34 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let prices = result.unwrap();
|
|
|
|
|
assert_eq!(prices.len(), 2);
|
|
|
|
|
assert!(prices.contains_key("0x123"));
|
|
|
|
|
assert!(prices.contains_key("0x456"));
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-12-04 02:28:34 -05:00
|
|
|
async fn test_get_server_time() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = "1234567890"; // Plain text response
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("GET", "/time")
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let result = client.get_server_time().await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-12-04 02:28:34 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let timestamp = result.unwrap();
|
|
|
|
|
assert_eq!(timestamp, 1234567890);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-12-04 02:28:34 -05:00
|
|
|
async fn test_create_or_derive_api_key() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"{
|
|
|
|
|
"apiKey": "test-api-key-123",
|
|
|
|
|
"secret": "test-secret-456",
|
|
|
|
|
"passphrase": "test-passphrase"
|
|
|
|
|
}"#;
|
|
|
|
|
|
|
|
|
|
// Mock both create and derive endpoints since the method tries both
|
|
|
|
|
let create_mock = server
|
|
|
|
|
.mock("POST", "/auth/api-key")
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client_with_auth(&server.url());
|
|
|
|
|
let result = client.create_or_derive_api_key(None).await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-12-04 02:28:34 -05:00
|
|
|
create_mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let api_creds = result.unwrap();
|
|
|
|
|
assert_eq!(api_creds.api_key, "test-api-key-123");
|
|
|
|
|
}
|
2026-01-29 18:28:42 -05:00
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
|
async fn test_create_or_derive_api_key_falls_back_on_api_error() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
|
|
|
|
|
// Create fails with a status error -> should fall back to derive.
|
|
|
|
|
let create_mock = server
|
|
|
|
|
.mock("POST", "/auth/api-key")
|
|
|
|
|
.with_status(400)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(r#"{"error":"key exists"}"#)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let derive_mock = server
|
|
|
|
|
.mock("GET", "/auth/derive-api-key")
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(
|
|
|
|
|
r#"{"apiKey":"derived-api-key","secret":"derived-secret","passphrase":"derived-pass"}"#,
|
|
|
|
|
)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client_with_auth(&server.url());
|
|
|
|
|
let result = client.create_or_derive_api_key(None).await;
|
|
|
|
|
|
|
|
|
|
create_mock.assert_async().await;
|
|
|
|
|
derive_mock.assert_async().await;
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
assert_eq!(result.unwrap().api_key, "derived-api-key");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
|
|
|
|
async fn test_create_or_derive_api_key_does_not_fallback_on_non_api_error() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
|
|
|
|
|
// Create returns 200 but with invalid JSON -> not an API status error.
|
|
|
|
|
let create_mock = server
|
|
|
|
|
.mock("POST", "/auth/api-key")
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body("not-json")
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
// If we incorrectly fall back, this would be called.
|
|
|
|
|
let derive_mock = server
|
|
|
|
|
.mock("GET", "/auth/derive-api-key")
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_body(
|
|
|
|
|
r#"{"apiKey":"derived-api-key","secret":"derived-secret","passphrase":"derived-pass"}"#,
|
|
|
|
|
)
|
|
|
|
|
.expect(0)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client_with_auth(&server.url());
|
|
|
|
|
let result = client.create_or_derive_api_key(None).await;
|
|
|
|
|
|
|
|
|
|
create_mock.assert_async().await;
|
|
|
|
|
derive_mock.assert_async().await;
|
|
|
|
|
assert!(result.is_err());
|
|
|
|
|
}
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-12-04 02:28:34 -05:00
|
|
|
async fn test_get_order_books_batch() {
|
|
|
|
|
let mut server = Server::new_async().await;
|
|
|
|
|
let mock_response = r#"[
|
|
|
|
|
{
|
|
|
|
|
"market": "0x123",
|
|
|
|
|
"asset_id": "0x123",
|
|
|
|
|
"hash": "test-hash",
|
|
|
|
|
"timestamp": "1234567890",
|
|
|
|
|
"bids": [{"price": "0.75", "size": "100.0"}],
|
2026-01-29 18:33:27 -05:00
|
|
|
"asks": [{"price": "0.76", "size": "50.0"}],
|
|
|
|
|
"min_order_size": "1",
|
|
|
|
|
"neg_risk": false,
|
|
|
|
|
"tick_size": "0.01",
|
|
|
|
|
"last_trade_price": null
|
2025-12-04 02:28:34 -05:00
|
|
|
}
|
|
|
|
|
]"#;
|
|
|
|
|
|
|
|
|
|
let mock = server
|
|
|
|
|
.mock("POST", "/books")
|
|
|
|
|
.with_header("content-type", "application/json")
|
|
|
|
|
.with_status(200)
|
|
|
|
|
.with_body(mock_response)
|
|
|
|
|
.create_async()
|
|
|
|
|
.await;
|
|
|
|
|
|
|
|
|
|
let client = create_test_client(&server.url());
|
|
|
|
|
let token_ids = vec!["0x123".to_string()];
|
|
|
|
|
let result = client.get_order_books(&token_ids).await;
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-12-04 02:28:34 -05:00
|
|
|
mock.assert_async().await;
|
|
|
|
|
if let Err(e) = &result {
|
|
|
|
|
println!("Error: {:?}", e);
|
|
|
|
|
}
|
|
|
|
|
assert!(result.is_ok());
|
|
|
|
|
let books = result.unwrap();
|
|
|
|
|
assert_eq!(books.len(), 1);
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-17 19:34:22 -05:00
|
|
|
#[tokio::test(flavor = "multi_thread")]
|
2025-12-04 02:28:34 -05:00
|
|
|
async fn test_order_args_creation() {
|
|
|
|
|
// Test OrderArgs creation and default values
|
2025-12-04 06:59:20 -05:00
|
|
|
let order_args = ClientOrderArgs::new(
|
2025-12-04 02:28:34 -05:00
|
|
|
"0x123",
|
|
|
|
|
Decimal::from_str("0.75").unwrap(),
|
|
|
|
|
Decimal::from_str("100.0").unwrap(),
|
|
|
|
|
Side::BUY,
|
|
|
|
|
);
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-12-04 02:28:34 -05:00
|
|
|
assert_eq!(order_args.token_id, "0x123");
|
|
|
|
|
assert_eq!(order_args.price, Decimal::from_str("0.75").unwrap());
|
|
|
|
|
assert_eq!(order_args.size, Decimal::from_str("100.0").unwrap());
|
|
|
|
|
assert_eq!(order_args.side, Side::BUY);
|
2025-12-05 19:09:06 -05:00
|
|
|
|
2025-12-04 02:28:34 -05:00
|
|
|
// Test default
|
2025-12-04 06:59:20 -05:00
|
|
|
let default_args = ClientOrderArgs::default();
|
2025-12-04 02:28:34 -05:00
|
|
|
assert_eq!(default_args.token_id, "");
|
|
|
|
|
assert_eq!(default_args.price, Decimal::ZERO);
|
|
|
|
|
assert_eq!(default_args.size, Decimal::ZERO);
|
|
|
|
|
assert_eq!(default_args.side, Side::BUY);
|
|
|
|
|
}
|
2025-12-05 19:09:06 -05:00
|
|
|
}
|