mirror of
https://github.com/floor-licker/polyfill-rs.git
synced 2026-08-20 16:08:07 +00:00
feat: migrate CLOB client to V2-only trading
This commit is contained in:
+19
-9
@@ -1,6 +1,6 @@
|
||||
//! Common utilities for integration tests
|
||||
|
||||
use polyfill_rs::{ClobClient, Result};
|
||||
use polyfill_rs::{ClientConfig, ClobClient, Result};
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -8,7 +8,7 @@ use std::time::Duration;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct TestConfig {
|
||||
pub host: String,
|
||||
pub chain_id: u64,
|
||||
pub chain: u64,
|
||||
pub private_key: Option<String>,
|
||||
pub api_key: Option<String>,
|
||||
pub api_secret: Option<String>,
|
||||
@@ -19,8 +19,9 @@ pub struct TestConfig {
|
||||
impl Default for TestConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
host: env::var("POLYMARKET_HOST").unwrap_or_else(|_| "https://clob.polymarket.com".to_string()),
|
||||
chain_id: env::var("POLYMARKET_CHAIN_ID")
|
||||
host: env::var("POLYMARKET_HOST")
|
||||
.unwrap_or_else(|_| "https://clob-v2.polymarket.com".to_string()),
|
||||
chain: env::var("POLYMARKET_CHAIN_ID")
|
||||
.unwrap_or_else(|_| "137".to_string())
|
||||
.parse()
|
||||
.unwrap_or(137),
|
||||
@@ -57,17 +58,26 @@ impl TestConfig {
|
||||
|
||||
/// Create an authenticated client for testing
|
||||
pub fn create_auth_client(&self) -> Result<ClobClient> {
|
||||
let private_key = self.private_key.as_ref()
|
||||
.ok_or_else(|| polyfill_rs::PolyfillError::auth("No private key provided", polyfill_rs::errors::AuthErrorKind::InvalidCredentials))?;
|
||||
|
||||
Ok(ClobClient::with_l1_headers(&self.host, private_key, self.chain_id))
|
||||
let private_key = self.private_key.as_ref().ok_or_else(|| {
|
||||
polyfill_rs::PolyfillError::auth(
|
||||
"No private key provided",
|
||||
polyfill_rs::errors::AuthErrorKind::InvalidCredentials,
|
||||
)
|
||||
})?;
|
||||
|
||||
ClobClient::from_config(ClientConfig {
|
||||
base_url: self.host.clone(),
|
||||
chain: self.chain,
|
||||
private_key: Some(private_key.clone()),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
}
|
||||
|
||||
/// Print test configuration (without sensitive data)
|
||||
pub fn print_config(&self) {
|
||||
println!("Test Configuration:");
|
||||
println!(" Host: {}", self.host);
|
||||
println!(" Chain ID: {}", self.chain_id);
|
||||
println!(" Chain ID: {}", self.chain);
|
||||
println!(" Has Auth: {}", self.has_auth());
|
||||
println!(" Has API Creds: {}", self.has_api_creds());
|
||||
println!(" Timeout: {:?}", self.test_timeout);
|
||||
|
||||
+51
-27
@@ -2,11 +2,11 @@
|
||||
// These tests hit the real Polymarket API and are ignored by default
|
||||
// Run with: cargo test --test integration_tests -- --ignored --test-threads=1
|
||||
|
||||
use polyfill_rs::{ClobClient, OrderArgs, Side};
|
||||
use polyfill_rs::{ClientConfig, ClobClient, OrderArgs, Side};
|
||||
use rust_decimal_macros::dec;
|
||||
use std::env;
|
||||
|
||||
const HOST: &str = "https://clob.polymarket.com";
|
||||
const HOST: &str = "https://clob-v2.polymarket.com";
|
||||
const CHAIN_ID: u64 = 137;
|
||||
|
||||
fn load_env_vars() -> (String, Option<String>, Option<String>, Option<String>) {
|
||||
@@ -21,12 +21,33 @@ fn load_env_vars() -> (String, Option<String>, Option<String>, Option<String>) {
|
||||
(private_key, api_key, api_secret, api_passphrase)
|
||||
}
|
||||
|
||||
fn bootstrap_client(private_key: &str) -> ClobClient {
|
||||
ClobClient::from_config(ClientConfig {
|
||||
base_url: HOST.to_string(),
|
||||
chain: CHAIN_ID,
|
||||
private_key: Some(private_key.to_string()),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build bootstrap client")
|
||||
}
|
||||
|
||||
fn authenticated_client(private_key: String, api_credentials: polyfill_rs::ApiCredentials) -> ClobClient {
|
||||
ClobClient::from_config(ClientConfig {
|
||||
base_url: HOST.to_string(),
|
||||
chain: CHAIN_ID,
|
||||
private_key: Some(private_key),
|
||||
api_credentials: Some(api_credentials),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build authenticated client")
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore]
|
||||
async fn test_real_api_create_derive_api_key() {
|
||||
let (private_key, _, _, _) = load_env_vars();
|
||||
|
||||
let client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let client = bootstrap_client(&private_key);
|
||||
|
||||
// Test creating/deriving API key
|
||||
let result = client.create_or_derive_api_key(None).await;
|
||||
@@ -50,15 +71,15 @@ async fn test_real_api_authenticated_order_flow() {
|
||||
let (private_key, _, _, _) = load_env_vars();
|
||||
|
||||
// Initialize client with L1 headers
|
||||
let mut client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let bootstrap = bootstrap_client(&private_key);
|
||||
|
||||
// Step 1: Create/derive API credentials
|
||||
println!("Step 1: Creating/deriving API credentials...");
|
||||
let api_creds = client
|
||||
let api_creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create/derive API key");
|
||||
client.set_api_creds(api_creds);
|
||||
let client = authenticated_client(private_key, api_creds);
|
||||
println!("PASS: API credentials set");
|
||||
|
||||
// Step 2: Get a valid token_id from active markets
|
||||
@@ -102,9 +123,12 @@ async fn test_real_api_authenticated_order_flow() {
|
||||
price: order_price,
|
||||
size: dec!(1.0), // Small size (auth is the thing we're testing here)
|
||||
side,
|
||||
expiration: None,
|
||||
builder_code: None,
|
||||
metadata: None,
|
||||
};
|
||||
|
||||
let post_result = client.create_and_post_order(&order_args).await;
|
||||
let post_result = client.create_and_post_order(&order_args, None, None).await;
|
||||
|
||||
// This is the critical test - did we get past the 401 error?
|
||||
match &post_result {
|
||||
@@ -112,9 +136,9 @@ async fn test_real_api_authenticated_order_flow() {
|
||||
println!("PASS: Order posted successfully!");
|
||||
|
||||
// Step 5: Cancel the order
|
||||
if let Some(order_id) = response.get("orderID").and_then(|v| v.as_str()) {
|
||||
println!("Step 5: Canceling order {}...", order_id);
|
||||
let cancel_result = client.cancel(order_id).await;
|
||||
if !response.order_id.is_empty() {
|
||||
println!("Step 5: Canceling order {}...", response.order_id);
|
||||
let cancel_result = client.cancel(&response.order_id).await;
|
||||
assert!(
|
||||
cancel_result.is_ok(),
|
||||
"Failed to cancel order: {:?}",
|
||||
@@ -156,12 +180,12 @@ async fn test_real_api_authenticated_order_flow() {
|
||||
async fn test_real_api_get_orders() {
|
||||
let (private_key, _, _, _) = load_env_vars();
|
||||
|
||||
let mut client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let api_creds = client
|
||||
let bootstrap = bootstrap_client(&private_key);
|
||||
let api_creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create/derive API key");
|
||||
client.set_api_creds(api_creds);
|
||||
let client = authenticated_client(private_key, api_creds);
|
||||
|
||||
println!("Testing get_orders...");
|
||||
let result = client.get_orders(None, None).await;
|
||||
@@ -186,12 +210,12 @@ async fn test_real_api_get_orders() {
|
||||
async fn test_real_api_get_trades() {
|
||||
let (private_key, _, _, _) = load_env_vars();
|
||||
|
||||
let mut client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let api_creds = client
|
||||
let bootstrap = bootstrap_client(&private_key);
|
||||
let api_creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create/derive API key");
|
||||
client.set_api_creds(api_creds);
|
||||
let client = authenticated_client(private_key, api_creds);
|
||||
|
||||
println!("Testing get_trades...");
|
||||
let result = client.get_trades(None, None).await;
|
||||
@@ -215,12 +239,12 @@ async fn test_real_api_get_trades() {
|
||||
async fn test_real_api_get_balance_allowance() {
|
||||
let (private_key, _, _, _) = load_env_vars();
|
||||
|
||||
let mut client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let api_creds = client
|
||||
let bootstrap = bootstrap_client(&private_key);
|
||||
let api_creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create/derive API key");
|
||||
client.set_api_creds(api_creds);
|
||||
let client = authenticated_client(private_key, api_creds);
|
||||
|
||||
println!("Testing get_balance_allowance...");
|
||||
|
||||
@@ -260,12 +284,12 @@ async fn test_real_api_get_balance_allowance() {
|
||||
async fn test_real_api_get_api_keys() {
|
||||
let (private_key, _, _, _) = load_env_vars();
|
||||
|
||||
let mut client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let api_creds = client
|
||||
let bootstrap = bootstrap_client(&private_key);
|
||||
let api_creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create/derive API key");
|
||||
client.set_api_creds(api_creds);
|
||||
let client = authenticated_client(private_key, api_creds);
|
||||
|
||||
println!("Testing get_api_keys...");
|
||||
let result = client.get_api_keys().await;
|
||||
@@ -290,12 +314,12 @@ async fn test_real_api_get_api_keys() {
|
||||
async fn test_real_api_get_notifications() {
|
||||
let (private_key, _, _, _) = load_env_vars();
|
||||
|
||||
let mut client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let api_creds = client
|
||||
let bootstrap = bootstrap_client(&private_key);
|
||||
let api_creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create/derive API key");
|
||||
client.set_api_creds(api_creds);
|
||||
let client = authenticated_client(private_key, api_creds);
|
||||
|
||||
println!("Testing get_notifications...");
|
||||
let result = client.get_notifications().await;
|
||||
@@ -320,7 +344,7 @@ async fn test_real_api_get_notifications() {
|
||||
async fn test_real_api_market_data_endpoints() {
|
||||
let (private_key, _, _, _) = load_env_vars();
|
||||
|
||||
let client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let client = bootstrap_client(&private_key);
|
||||
|
||||
println!("Testing market data endpoints (no auth required)...");
|
||||
|
||||
@@ -387,7 +411,7 @@ async fn test_real_api_market_data_endpoints() {
|
||||
async fn test_real_api_batch_endpoints() {
|
||||
let (private_key, _, _, _) = load_env_vars();
|
||||
|
||||
let client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let client = bootstrap_client(&private_key);
|
||||
|
||||
println!("Testing batch endpoints...");
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Test order posting - the critical endpoint that had the 401 bug
|
||||
use polyfill_rs::{ClobClient, OrderArgs, Side};
|
||||
use polyfill_rs::{ClientConfig, ClobClient, OrderArgs, Side};
|
||||
use rust_decimal::Decimal;
|
||||
use std::env;
|
||||
use std::str::FromStr;
|
||||
@@ -12,14 +12,27 @@ async fn test_post_order_authentication() {
|
||||
let private_key =
|
||||
env::var("POLYMARKET_PRIVATE_KEY").expect("POLYMARKET_PRIVATE_KEY must be set in .env");
|
||||
|
||||
let mut client = ClobClient::with_l1_headers("https://clob.polymarket.com", &private_key, 137);
|
||||
let bootstrap = ClobClient::from_config(ClientConfig {
|
||||
base_url: "https://clob-v2.polymarket.com".to_string(),
|
||||
chain: 137,
|
||||
private_key: Some(private_key.clone()),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build bootstrap client");
|
||||
|
||||
println!("Step 1: Creating API credentials...");
|
||||
let creds = client
|
||||
let creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create API key");
|
||||
client.set_api_creds(creds);
|
||||
let client = ClobClient::from_config(ClientConfig {
|
||||
base_url: "https://clob-v2.polymarket.com".to_string(),
|
||||
chain: 137,
|
||||
private_key: Some(private_key),
|
||||
api_credentials: Some(creds),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build authenticated client");
|
||||
println!("API credentials set");
|
||||
|
||||
// Use a well-known token ID (we'll use an extreme price so it won't fill)
|
||||
@@ -31,9 +44,12 @@ async fn test_post_order_authentication() {
|
||||
price: Decimal::from_str("0.01").unwrap(), // Very low price, won't fill
|
||||
size: Decimal::from_str("1.0").unwrap(),
|
||||
side: Side::BUY,
|
||||
expiration: None,
|
||||
builder_code: None,
|
||||
metadata: None,
|
||||
};
|
||||
|
||||
let result = client.create_and_post_order(&order_args).await;
|
||||
let result = client.create_and_post_order(&order_args, None, None).await;
|
||||
|
||||
match result {
|
||||
Ok(response) => {
|
||||
@@ -41,9 +57,9 @@ async fn test_post_order_authentication() {
|
||||
println!(" Response: {:?}", response);
|
||||
|
||||
// Try to cancel it if we got an order ID
|
||||
if let Some(order_id) = response.get("orderID").and_then(|v| v.as_str()) {
|
||||
if !response.order_id.is_empty() {
|
||||
println!("\nStep 3: Canceling order...");
|
||||
match client.cancel(order_id).await {
|
||||
match client.cancel(&response.order_id).await {
|
||||
Ok(_) => println!("Order canceled successfully"),
|
||||
Err(e) => println!("Cancel failed (order might have expired): {:?}", e),
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
use polyfill_rs::{ClobClient, PricesHistoryInterval};
|
||||
|
||||
const HOST: &str = "https://clob.polymarket.com";
|
||||
const HOST: &str = "https://clob-v2.polymarket.com";
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore]
|
||||
|
||||
+51
-13
@@ -1,7 +1,17 @@
|
||||
// Simple authentication test to verify HMAC works
|
||||
use polyfill_rs::ClobClient;
|
||||
use polyfill_rs::{ClientConfig, ClobClient};
|
||||
use std::env;
|
||||
|
||||
fn build_bootstrap_client(private_key: &str) -> ClobClient {
|
||||
ClobClient::from_config(ClientConfig {
|
||||
base_url: "https://clob-v2.polymarket.com".to_string(),
|
||||
chain: 137,
|
||||
private_key: Some(private_key.to_string()),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build bootstrap client")
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[ignore]
|
||||
async fn test_create_api_key_simple() {
|
||||
@@ -10,16 +20,23 @@ async fn test_create_api_key_simple() {
|
||||
let private_key =
|
||||
env::var("POLYMARKET_PRIVATE_KEY").expect("POLYMARKET_PRIVATE_KEY must be set in .env");
|
||||
|
||||
let mut client = ClobClient::with_l1_headers("https://clob.polymarket.com", &private_key, 137);
|
||||
let bootstrap = build_bootstrap_client(&private_key);
|
||||
|
||||
println!("Step 1: Creating/deriving API key...");
|
||||
let result = client.create_or_derive_api_key(None).await;
|
||||
let result = bootstrap.create_or_derive_api_key(None).await;
|
||||
|
||||
match result {
|
||||
Ok(creds) => {
|
||||
println!("Successfully created/derived API key");
|
||||
println!(" API Key created (len={})", creds.api_key.len());
|
||||
client.set_api_creds(creds);
|
||||
let client = ClobClient::from_config(ClientConfig {
|
||||
base_url: "https://clob-v2.polymarket.com".to_string(),
|
||||
chain: 137,
|
||||
private_key: Some(private_key),
|
||||
api_credentials: Some(creds),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build authenticated client");
|
||||
|
||||
// Now try to get orders (requires auth)
|
||||
println!("\nStep 2: Testing authenticated endpoint (get_orders)...");
|
||||
@@ -53,13 +70,20 @@ async fn test_get_api_keys() {
|
||||
let private_key =
|
||||
env::var("POLYMARKET_PRIVATE_KEY").expect("POLYMARKET_PRIVATE_KEY must be set in .env");
|
||||
|
||||
let mut client = ClobClient::with_l1_headers("https://clob.polymarket.com", &private_key, 137);
|
||||
let bootstrap = build_bootstrap_client(&private_key);
|
||||
|
||||
let creds = client
|
||||
let creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create API key");
|
||||
client.set_api_creds(creds);
|
||||
let client = ClobClient::from_config(ClientConfig {
|
||||
base_url: "https://clob-v2.polymarket.com".to_string(),
|
||||
chain: 137,
|
||||
private_key: Some(private_key),
|
||||
api_credentials: Some(creds),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build authenticated client");
|
||||
|
||||
println!("Testing get_api_keys (requires HMAC auth)...");
|
||||
let result = client.get_api_keys().await;
|
||||
@@ -87,13 +111,20 @@ async fn test_get_trades() {
|
||||
let private_key =
|
||||
env::var("POLYMARKET_PRIVATE_KEY").expect("POLYMARKET_PRIVATE_KEY must be set in .env");
|
||||
|
||||
let mut client = ClobClient::with_l1_headers("https://clob.polymarket.com", &private_key, 137);
|
||||
let bootstrap = build_bootstrap_client(&private_key);
|
||||
|
||||
let creds = client
|
||||
let creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create API key");
|
||||
client.set_api_creds(creds);
|
||||
let client = ClobClient::from_config(ClientConfig {
|
||||
base_url: "https://clob-v2.polymarket.com".to_string(),
|
||||
chain: 137,
|
||||
private_key: Some(private_key),
|
||||
api_credentials: Some(creds),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build authenticated client");
|
||||
|
||||
println!("Testing get_trades (requires HMAC auth)...");
|
||||
let result = client.get_trades(None, None).await;
|
||||
@@ -121,13 +152,20 @@ async fn test_get_notifications() {
|
||||
let private_key =
|
||||
env::var("POLYMARKET_PRIVATE_KEY").expect("POLYMARKET_PRIVATE_KEY must be set in .env");
|
||||
|
||||
let mut client = ClobClient::with_l1_headers("https://clob.polymarket.com", &private_key, 137);
|
||||
let bootstrap = build_bootstrap_client(&private_key);
|
||||
|
||||
let creds = client
|
||||
let creds = bootstrap
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
.expect("Failed to create API key");
|
||||
client.set_api_creds(creds);
|
||||
let client = ClobClient::from_config(ClientConfig {
|
||||
base_url: "https://clob-v2.polymarket.com".to_string(),
|
||||
chain: 137,
|
||||
private_key: Some(private_key),
|
||||
api_credentials: Some(creds),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build authenticated client");
|
||||
|
||||
println!("Testing get_notifications (requires HMAC auth)...");
|
||||
let result = client.get_notifications().await;
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
#![cfg(feature = "stream")]
|
||||
|
||||
use futures::StreamExt;
|
||||
use polyfill_rs::{ClobClient, OrderBookManager, WebSocketStream, WsBookUpdateProcessor};
|
||||
use polyfill_rs::{ClientConfig, ClobClient, OrderBookManager, WebSocketStream, WsBookUpdateProcessor};
|
||||
use std::env;
|
||||
use std::time::Duration;
|
||||
|
||||
const HOST: &str = "https://clob.polymarket.com";
|
||||
const HOST: &str = "https://clob-v2.polymarket.com";
|
||||
const WS_MARKET_URL: &str = "wss://ws-subscriptions-clob.polymarket.com/ws/market";
|
||||
const WS_USER_URL: &str = "wss://ws-subscriptions-clob.polymarket.com/ws/user";
|
||||
const CHAIN_ID: u64 = 137;
|
||||
@@ -147,7 +147,13 @@ async fn test_real_ws_user_channel_connection_stable() {
|
||||
// during the window. This test primarily asserts we can authenticate + subscribe
|
||||
// and that the connection doesn't immediately drop.
|
||||
let private_key = load_private_key();
|
||||
let auth_client = ClobClient::with_l1_headers(HOST, &private_key, CHAIN_ID);
|
||||
let auth_client = ClobClient::from_config(ClientConfig {
|
||||
base_url: HOST.to_string(),
|
||||
chain: CHAIN_ID,
|
||||
private_key: Some(private_key),
|
||||
..ClientConfig::default()
|
||||
})
|
||||
.expect("failed to build authenticated client");
|
||||
let api_creds = auth_client
|
||||
.create_or_derive_api_key(None)
|
||||
.await
|
||||
|
||||
Reference in New Issue
Block a user