polymarket 0.1.0

Rust SDK for Polymarket prediction market - CLOB trading, on-chain operations, and WebSocket streaming
Documentation
/// Data API client for fetching user positions, trades, and activity
///
/// Reference: https://docs.polymarket.com/api-reference/core

use super::types::*;
use reqwest;

/// Client for Polymarket Data API
#[derive(Clone)]
pub struct DataClient {
    base_url: String,
    client: reqwest::Client,
}

impl DataClient {
    /// Create a new DataClient
    ///
    /// # Arguments
    /// * `base_url` - Base URL for the Data API (default: https://data-api.polymarket.com)
    pub fn new(base_url: String) -> Self {
        Self {
            base_url,
            client: reqwest::Client::new(),
        }
    }

    /// Create a DataClient with default URL
    pub fn default() -> Self {
        Self::new("https://data-api.polymarket.com".to_string())
    }

    // ============================================================================
    // Position Endpoints
    // ============================================================================

    /// Get current positions for a user
    ///
    /// Reference: https://docs.polymarket.com/api-reference/core/get-current-positions-for-a-user
    ///
    /// # Arguments
    /// * `address` - User wallet address
    pub async fn get_positions(&self, address: &str) -> Result<Vec<Position>, reqwest::Error> {
        let url = format!("{}/positions", self.base_url);

        let response = self.client
            .get(&url)
            .query(&[("user", address)])
            .send()
            .await?;

        let positions: Vec<Position> = response.json().await?;

        Ok(positions)
    }

    /// Get total value of a user's positions
    ///
    /// Reference: https://docs.polymarket.com/api-reference/core/get-total-value-of-a-users-positions
    ///
    /// # Arguments
    /// * `address` - User wallet address
    pub async fn get_portfolio_value(&self, address: &str) -> Result<PortfolioValue, reqwest::Error> {
        let url = format!("{}/portfolio/{}", self.base_url, address);

        let response = self.client.get(&url).send().await?;
        let value: PortfolioValue = response.json().await?;

        Ok(value)
    }

    /// Get closed positions for a user
    ///
    /// Reference: https://docs.polymarket.com/api-reference/core/get-closed-positions-for-a-user
    ///
    /// # Arguments
    /// * `address` - User wallet address
    /// * `limit` - Optional limit on number of results
    /// * `offset` - Optional offset for pagination
    pub async fn get_closed_positions(
        &self,
        address: &str,
        limit: Option<u32>,
        offset: Option<u32>,
    ) -> Result<Vec<ClosedPosition>, reqwest::Error> {
        let url = format!("{}/closed-positions", self.base_url);

        let mut request = self.client.get(&url).query(&[("user", address)]);

        if let Some(l) = limit {
            request = request.query(&[("limit", l.to_string())]);
        }
        if let Some(o) = offset {
            request = request.query(&[("offset", o.to_string())]);
        }

        let response = request.send().await?;
        let positions: Vec<ClosedPosition> = response.json().await?;

        Ok(positions)
    }

    // ============================================================================
    // Trade Endpoints
    // ============================================================================

    /// Get trades for a user or markets
    ///
    /// Reference: https://docs.polymarket.com/api-reference/core/get-trades-for-a-user-or-markets
    ///
    /// # Arguments
    /// * `address` - User wallet address
    /// * `market` - Optional market ID to filter by
    /// * `limit` - Optional limit on number of results
    /// * `offset` - Optional offset for pagination
    pub async fn get_trades(
        &self,
        address: &str,
        market: Option<&str>,
        limit: Option<u32>,
        offset: Option<u32>,
    ) -> Result<Vec<Trade>, reqwest::Error> {
        let url = format!("{}/trades", self.base_url);

        let mut request = self.client.get(&url).query(&[("user", address)]);

        if let Some(m) = market {
            request = request.query(&[("market", m)]);
        }
        if let Some(l) = limit {
            request = request.query(&[("limit", l.to_string())]);
        }
        if let Some(o) = offset {
            request = request.query(&[("offset", o.to_string())]);
        }

        let response = request.send().await?;
        let trades: Vec<Trade> = response.json().await?;

        Ok(trades)
    }

    // ============================================================================
    // Activity Endpoints
    // ============================================================================

    /// Get user activity
    ///
    /// Reference: https://docs.polymarket.com/api-reference/core/get-user-activity
    ///
    /// # Arguments
    /// * `address` - User wallet address
    /// * `limit` - Optional limit on number of results
    /// * `offset` - Optional offset for pagination
    pub async fn get_activity(
        &self,
        address: &str,
        limit: Option<u32>,
        offset: Option<u32>,
    ) -> Result<Vec<Activity>, reqwest::Error> {
        let mut url = format!("{}/activity/{}", self.base_url, address);

        let mut params = vec![];
        if let Some(l) = limit {
            params.push(format!("limit={}", l));
        }
        if let Some(o) = offset {
            params.push(format!("offset={}", o));
        }

        if !params.is_empty() {
            url = format!("{}?{}", url, params.join("&"));
        }

        let response = self.client.get(&url).send().await?;
        let activities: Vec<Activity> = response.json().await?;

        Ok(activities)
    }

    // ============================================================================
    // Statistics Endpoints
    // ============================================================================

    /// Get total markets a user has traded
    ///
    /// Reference: https://docs.polymarket.com/api-reference/misc/get-total-markets-a-user-has-traded
    ///
    /// # Arguments
    /// * `address` - User wallet address
    pub async fn get_markets_traded(&self, address: &str) -> Result<MarketsTraded, reqwest::Error> {
        let url = format!("{}/markets-traded/{}", self.base_url, address);

        let response = self.client.get(&url).send().await?;
        let result: MarketsTraded = response.json().await?;

        Ok(result)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_client_creation() {
        let client = DataClient::default();
        assert_eq!(client.base_url, "https://data-api.polymarket.com");
    }

    #[test]
    fn test_client_with_custom_url() {
        let client = DataClient::new("https://custom-api.example.com".to_string());
        assert_eq!(client.base_url, "https://custom-api.example.com");
    }

    // Note: Integration tests would require a real API or mock server
    // and should be run with #[ignore] or in a separate test suite
}