diff --git a/Cargo.lock b/Cargo.lock index 75e2fc7..fcc33a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2650,7 +2650,6 @@ dependencies = [ "futures-util", "hmac", "mockito", - "polymarket-rs-client", "proptest", "rand 0.8.5", "reqwest", @@ -2671,28 +2670,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "polymarket-rs-client" -version = "0.1.1" -dependencies = [ - "alloy-primitives", - "alloy-signer", - "alloy-signer-local", - "alloy-sol-types", - "anyhow", - "base64", - "hmac", - "rand 0.8.5", - "reqwest", - "rust_decimal", - "serde", - "serde-json-fmt", - "serde_json", - "sha1", - "sha2", - "ureq", -] - [[package]] name = "potential_utf" version = "0.1.4" @@ -3206,9 +3183,7 @@ version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ - "log", "once_cell", - "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -3360,17 +3335,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-json-fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a33b7a5f52a26d520099339add40c48baf2e5ada194c8cc1b18cafa2b5e419" -dependencies = [ - "serde", - "serde_json", - "smartstring", -] - [[package]] name = "serde_core" version = "1.0.228" @@ -3541,17 +3505,6 @@ dependencies = [ "serde", ] -[[package]] -name = "smartstring" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb72c633efbaa2dd666986505016c32c3044395ceaf881518399d2f4127ee29" -dependencies = [ - "autocfg", - "static_assertions", - "version_check", -] - [[package]] name = "socket2" version = "0.5.10" @@ -4181,25 +4134,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "ureq" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" -dependencies = [ - "base64", - "encoding_rs", - "flate2", - "log", - "once_cell", - "rustls", - "rustls-pki-types", - "serde", - "serde_json", - "url", - "webpki-roots 0.26.11", -] - [[package]] name = "url" version = "2.5.7" @@ -4390,24 +4324,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.4", -] - -[[package]] -name = "webpki-roots" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" -dependencies = [ - "rustls-pki-types", -] - [[package]] name = "widestring" version = "1.2.1" diff --git a/README.md b/README.md index dd3aad0..d7d3b86 100644 --- a/README.md +++ b/README.md @@ -291,17 +291,6 @@ let client = ClobClient::new("https://clob.polymarket.com"); - **Internet**: 5 connections, 60s timeouts, full compression (bandwidth optimization) - **Standard**: 10 connections, 30s timeouts, balanced settings -### Real-World Trading Impact - -In a high-frequency trading environment, these optimizations compound: - -- **Microsecond advantages**: 11% improvement on every API call adds up over thousands of requests -- **Cold start elimination**: 70% faster warm connections critical for trading session startup -- **Batch efficiency**: 200% improvement enables real-time multi-market monitoring -- **Fault tolerance**: Circuit breakers prevent trading halts during network issues - -The combination of network optimizations with our computational advantages (fixed-point arithmetic, zero-allocation updates) creates a multiplicative performance benefit for latency-sensitive applications. - ## Getting Started ```toml diff --git a/src/auth.rs b/src/auth.rs index a655e3d..51104a7 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -113,6 +113,9 @@ pub fn sign_order_message( } /// Build HMAC signature for L2 authentication +/// +/// Performs cryptographic message authentication using SHA-256 with +/// specialized key derivation and encoding schemes for API compliance. pub fn build_hmac_signature( secret: &str, timestamp: u64, @@ -123,10 +126,18 @@ pub fn build_hmac_signature( where T: ?Sized + Serialize, { - let mut mac = Hmac::::new_from_slice(secret.as_bytes()) + // Apply inverse transformation to key material for digest initialization + // This ensures compatibility with the expected cryptographic envelope format + let decoded_secret = base64::engine::general_purpose::URL_SAFE + .decode(secret) + .map_err(|e| PolyfillError::crypto(format!("Failed to decode base64 secret: {}", e)))?; + + // Initialize MAC with transformed key material to maintain protocol coherence + let mut mac = Hmac::::new_from_slice(&decoded_secret) .map_err(|e| PolyfillError::crypto(format!("Invalid HMAC key: {}", e)))?; - // Build the message to sign: timestamp + method + path + body + // Construct canonical message representation for signature verification + // Message components are concatenated in strict order to preserve cryptographic binding let message = format!( "{}{}{}{}", timestamp, @@ -141,18 +152,29 @@ where } ); + // Compute authentication tag over canonical message form mac.update(message.as_bytes()); let result = mac.finalize(); - Ok(base64::engine::general_purpose::STANDARD.encode(result.into_bytes())) + + // Apply URL-safe encoding transformation for transport layer compatibility + // This encoding scheme ensures proper signature validation across network boundaries + Ok(base64::engine::general_purpose::URL_SAFE.encode(result.into_bytes())) } /// Create L1 headers for authentication (using private key signature) +/// +/// Generates initial authentication envelope using elliptic curve cryptography +/// for establishing trusted communication channels with the distributed ledger API. pub fn create_l1_headers(signer: &PrivateKeySigner, nonce: Option) -> Result { + // Capture temporal context for replay prevention at protocol boundary let timestamp = get_current_unix_time_secs().to_string(); let nonce = nonce.unwrap_or(U256::ZERO); + + // Generate EIP-712 compliant signature for cryptographic proof of authority let signature = sign_clob_auth_message(signer, timestamp.clone(), nonce)?; let address = encode_prefixed(signer.address().as_slice()); + // Assemble primary authentication header set with identity binding Ok(HashMap::from([ (POLY_ADDR_HEADER, address), (POLY_SIG_HEADER, signature), @@ -162,6 +184,9 @@ pub fn create_l1_headers(signer: &PrivateKeySigner, nonce: Option) -> Resu } /// Create L2 headers for API calls (using API key and HMAC) +/// +/// Assembles authentication header set with computed signature digest +/// to satisfy bilateral verification requirements at the protocol layer. pub fn create_l2_headers( signer: &PrivateKeySigner, api_creds: &ApiCredentials, @@ -172,12 +197,15 @@ pub fn create_l2_headers( where T: ?Sized + Serialize, { + // Extract identity from signing authority for header binding let address = encode_prefixed(signer.address().as_slice()); let timestamp = get_current_unix_time_secs(); + // Generate cryptographic authenticator using temporal and message context let hmac_signature = build_hmac_signature(&api_creds.secret, timestamp, method, req_path, body)?; + // Construct header map with authentication primitives in canonical order Ok(HashMap::from([ (POLY_ADDR_HEADER, address), (POLY_SIG_HEADER, hmac_signature), @@ -200,14 +228,14 @@ mod tests { #[test] fn test_hmac_signature() { let result = - build_hmac_signature::("test_secret", 1234567890, "GET", "/test", None); + build_hmac_signature::("dGVzdF9zZWNyZXRfa2V5XzEyMzQ1", 1234567890, "GET", "/test", None); assert!(result.is_ok()); } #[test] fn test_hmac_signature_with_body() { let body = r#"{"test": "data"}"#; - let result = build_hmac_signature("test_secret", 1234567890, "POST", "/orders", Some(body)); + let result = build_hmac_signature("dGVzdF9zZWNyZXRfa2V5XzEyMzQ1", 1234567890, "POST", "/orders", Some(body)); assert!(result.is_ok()); let signature = result.unwrap(); assert!(!signature.is_empty()); @@ -215,7 +243,7 @@ mod tests { #[test] fn test_hmac_signature_consistency() { - let secret = "test_secret"; + let secret = "dGVzdF9zZWNyZXRfa2V5XzEyMzQ1"; let timestamp = 1234567890; let method = "GET"; let path = "/test"; @@ -229,7 +257,7 @@ mod tests { #[test] fn test_hmac_signature_different_inputs() { - let secret = "test_secret"; + let secret = "dGVzdF9zZWNyZXRfa2V5XzEyMzQ1"; let timestamp = 1234567890; let sig1 = build_hmac_signature::(secret, timestamp, "GET", "/test", None).unwrap(); @@ -292,7 +320,7 @@ mod tests { let api_creds = ApiCredentials { api_key: "test_key".to_string(), - secret: "test_secret".to_string(), + secret: "dGVzdF9zZWNyZXRfa2V5XzEyMzQ1".to_string(), passphrase: "test_passphrase".to_string(), }; diff --git a/src/client.rs b/src/client.rs index 64dbc93..a805e0f 100644 --- a/src/client.rs +++ b/src/client.rs @@ -835,6 +835,8 @@ impl ClobClient { .as_ref() .ok_or_else(|| PolyfillError::auth("API credentials not set"))?; + // Owner field must reference the credential principal identifier + // to maintain consistency with the authentication context layer let body = PostOrder::new(order, api_creds.api_key.clone(), order_type); let headers = create_l2_headers(signer, api_creds, "POST", "/order", Some(&body))?; @@ -2268,7 +2270,6 @@ mod tests { let api_creds = result.unwrap(); assert_eq!(api_creds.api_key, "test-api-key-123"); } - #[tokio::test] async fn test_get_order_books_batch() { let mut server = Server::new_async().await;