test: support live DNS override and credential aliases

This commit is contained in:
floor-licker
2026-04-28 10:05:22 -03:00
parent f7638310b0
commit eac25be5b2
4 changed files with 51 additions and 7 deletions
+13
View File
@@ -45,9 +45,17 @@ export POLYMARKET_API_KEY="your_api_key"
export POLYMARKET_API_SECRET="your_api_secret" export POLYMARKET_API_SECRET="your_api_secret"
export POLYMARKET_API_PASSPHRASE="your_passphrase" export POLYMARKET_API_PASSPHRASE="your_passphrase"
# Backward-compatible aliases also accepted by test helpers
export POLYMARKET_SECRET="your_api_secret"
export POLYMARKET_PASSPHRASE="your_passphrase"
# Optional (defaults provided in test helpers) # Optional (defaults provided in test helpers)
export POLYMARKET_HOST="https://clob.polymarket.com" export POLYMARKET_HOST="https://clob.polymarket.com"
export POLYMARKET_CHAIN_ID="137" export POLYMARKET_CHAIN_ID="137"
# Optional: pin clob.polymarket.com to a known A record if local DNS is blocked.
# Keep the hostname in POLYMARKET_HOST so HTTPS/SNI still validates.
export POLYMARKET_RESOLVE_IP="104.18.34.205"
``` ```
#### 2. Run Integration Tests #### 2. Run Integration Tests
@@ -126,6 +134,11 @@ curl -I https://clob.polymarket.com/
# Check DNS resolution # Check DNS resolution
nslookup clob.polymarket.com nslookup clob.polymarket.com
# If local DNS fails but outbound HTTPS works, get a current A record and pin it:
curl -sS -H 'accept:application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=clob.polymarket.com&type=A'
export POLYMARKET_RESOLVE_IP="104.18.34.205"
``` ```
#### Authentication Issues #### Authentication Issues
+26 -3
View File
@@ -19,6 +19,7 @@ use reqwest::{Method, RequestBuilder};
use rust_decimal::prelude::FromPrimitive; use rust_decimal::prelude::FromPrimitive;
use rust_decimal::Decimal; use rust_decimal::Decimal;
use serde_json::Value; use serde_json::Value;
use std::net::{IpAddr, SocketAddr};
use std::str::FromStr; use std::str::FromStr;
use std::time::Duration; use std::time::Duration;
@@ -30,7 +31,11 @@ struct MarketByTokenResponse {
condition_id: String, condition_id: String,
} }
fn build_http_client(timeout: Option<Duration>, max_connections: Option<usize>) -> Client { fn build_http_client(
host: &str,
timeout: Option<Duration>,
max_connections: Option<usize>,
) -> Client {
let max_connections = max_connections.unwrap_or(10); let max_connections = max_connections.unwrap_or(10);
let mut builder = reqwest::ClientBuilder::new() let mut builder = reqwest::ClientBuilder::new()
.no_proxy() .no_proxy()
@@ -44,6 +49,14 @@ fn build_http_client(timeout: Option<Duration>, max_connections: Option<usize>)
builder = builder.timeout(timeout); builder = builder.timeout(timeout);
} }
if let Ok(resolve_ip) = std::env::var("POLYMARKET_RESOLVE_IP") {
if let Ok(ip) = resolve_ip.parse::<IpAddr>() {
if let Some(hostname) = extract_hostname(host) {
builder = builder.resolve(hostname, SocketAddr::new(ip, 443));
}
}
}
builder.build().unwrap_or_else(|_| { builder.build().unwrap_or_else(|_| {
reqwest::ClientBuilder::new() reqwest::ClientBuilder::new()
.no_proxy() .no_proxy()
@@ -52,6 +65,15 @@ fn build_http_client(timeout: Option<Duration>, max_connections: Option<usize>)
}) })
} }
fn extract_hostname(host: &str) -> Option<&str> {
host.trim_start_matches("https://")
.trim_start_matches("http://")
.split('/')
.next()
.and_then(|authority| authority.split(':').next())
.filter(|hostname| !hostname.is_empty())
}
/// Main client for interacting with Polymarket API /// Main client for interacting with Polymarket API
pub struct ClobClient { pub struct ClobClient {
pub http_client: Client, pub http_client: Client,
@@ -129,7 +151,7 @@ impl ClobClient {
/// Create a new client with optimized HTTP/2 settings (benchmarked 11.4% faster) /// Create a new client with optimized HTTP/2 settings (benchmarked 11.4% faster)
/// Now includes DNS caching, connection management, and buffer pooling /// Now includes DNS caching, connection management, and buffer pooling
pub fn new(host: &str) -> Self { pub fn new(host: &str) -> Self {
let http_client = build_http_client(None, None); let http_client = build_http_client(host, None, None);
Self::build_client(host, 137, http_client, None, None, None) Self::build_client(host, 137, http_client, None, None, None)
} }
@@ -144,7 +166,8 @@ impl ClobClient {
None => None, None => None,
}; };
let http_client = build_http_client(config.timeout, config.max_connections); let http_client =
build_http_client(&config.base_url, config.timeout, config.max_connections);
Ok(Self::build_client( Ok(Self::build_client(
&config.base_url, &config.base_url,
+6 -2
View File
@@ -27,8 +27,12 @@ impl Default for TestConfig {
.unwrap_or(137), .unwrap_or(137),
private_key: env::var("POLYMARKET_PRIVATE_KEY").ok(), private_key: env::var("POLYMARKET_PRIVATE_KEY").ok(),
api_key: env::var("POLYMARKET_API_KEY").ok(), api_key: env::var("POLYMARKET_API_KEY").ok(),
api_secret: env::var("POLYMARKET_API_SECRET").ok(), api_secret: env::var("POLYMARKET_API_SECRET")
api_passphrase: env::var("POLYMARKET_API_PASSPHRASE").ok(), .or_else(|_| env::var("POLYMARKET_SECRET"))
.ok(),
api_passphrase: env::var("POLYMARKET_API_PASSPHRASE")
.or_else(|_| env::var("POLYMARKET_PASSPHRASE"))
.ok(),
test_timeout: Duration::from_secs(30), test_timeout: Duration::from_secs(30),
} }
} }
+6 -2
View File
@@ -15,8 +15,12 @@ fn load_env_vars() -> (String, Option<String>, Option<String>, Option<String>) {
let private_key = let private_key =
env::var("POLYMARKET_PRIVATE_KEY").expect("POLYMARKET_PRIVATE_KEY must be set in .env"); env::var("POLYMARKET_PRIVATE_KEY").expect("POLYMARKET_PRIVATE_KEY must be set in .env");
let api_key = env::var("POLYMARKET_API_KEY").ok(); let api_key = env::var("POLYMARKET_API_KEY").ok();
let api_secret = env::var("POLYMARKET_API_SECRET").ok(); let api_secret = env::var("POLYMARKET_API_SECRET")
let api_passphrase = env::var("POLYMARKET_API_PASSPHRASE").ok(); .or_else(|_| env::var("POLYMARKET_SECRET"))
.ok();
let api_passphrase = env::var("POLYMARKET_API_PASSPHRASE")
.or_else(|_| env::var("POLYMARKET_PASSPHRASE"))
.ok();
(private_key, api_key, api_secret, api_passphrase) (private_key, api_key, api_secret, api_passphrase)
} }