use px_core::ExchangeConfig;
pub const GAMMA_API_URL: &str = "https://gamma-api.polymarket.com";
pub const CLOB_API_URL: &str = "https://clob.polymarket.com";
pub const DATA_API_URL: &str = "https://data-api.polymarket.com";
pub const DEFAULT_POLYGON_RPC: &str = "https://polygon-bor-rpc.publicnode.com";
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum PolymarketSignatureType {
#[default]
Eoa = 0,
Proxy = 1,
GnosisSafe = 2,
}
impl From<PolymarketSignatureType> for u8 {
fn from(t: PolymarketSignatureType) -> u8 {
t as u8
}
}
impl From<&str> for PolymarketSignatureType {
fn from(s: &str) -> Self {
match s.to_lowercase().as_str() {
"proxy" | "browser" | "poly_proxy" | "1" => Self::Proxy,
"gnosis" | "gnosissafe" | "gnosis_safe" | "safe" | "poly_gnosis_safe" | "2" => {
Self::GnosisSafe
}
_ => Self::Eoa,
}
}
}
#[derive(Debug, Clone)]
pub struct PolymarketConfig {
pub base: ExchangeConfig,
pub gamma_url: String,
pub clob_url: String,
pub data_api_url: String,
pub private_key: Option<String>,
pub funder: Option<String>,
pub signature_type: PolymarketSignatureType,
pub chain_id: u64,
pub api_key: Option<String>,
pub api_secret: Option<String>,
pub api_passphrase: Option<String>,
pub polygon_rpc_url: Option<String>,
pub builder_api_key: Option<String>,
pub builder_secret: Option<String>,
pub builder_passphrase: Option<String>,
}
impl Default for PolymarketConfig {
fn default() -> Self {
Self {
base: ExchangeConfig {
rate_limit_per_second: 50, ..ExchangeConfig::default()
},
gamma_url: GAMMA_API_URL.into(),
clob_url: CLOB_API_URL.into(),
data_api_url: DATA_API_URL.into(),
private_key: None,
funder: None,
signature_type: PolymarketSignatureType::default(),
chain_id: 137,
api_key: None,
api_secret: None,
api_passphrase: None,
polygon_rpc_url: None,
builder_api_key: None,
builder_secret: None,
builder_passphrase: None,
}
}
}
impl PolymarketConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_private_key(mut self, key: impl Into<String>) -> Self {
self.private_key = Some(key.into());
self
}
pub fn with_funder(mut self, funder: impl Into<String>) -> Self {
self.funder = Some(funder.into());
self
}
pub fn with_signature_type(mut self, sig_type: PolymarketSignatureType) -> Self {
self.signature_type = sig_type;
self
}
pub fn with_verbose(mut self, verbose: bool) -> Self {
self.base = self.base.with_verbose(verbose);
self
}
pub fn with_gamma_url(mut self, url: impl Into<String>) -> Self {
self.gamma_url = url.into();
self
}
pub fn with_clob_url(mut self, url: impl Into<String>) -> Self {
self.clob_url = url.into();
self
}
pub fn with_api_credentials(
mut self,
key: impl Into<String>,
secret: impl Into<String>,
passphrase: impl Into<String>,
) -> Self {
self.api_key = Some(key.into());
self.api_secret = Some(secret.into());
self.api_passphrase = Some(passphrase.into());
self
}
pub fn with_polygon_rpc(mut self, url: impl Into<String>) -> Self {
self.polygon_rpc_url = Some(url.into());
self
}
pub fn with_builder_credentials(
mut self,
key: impl Into<String>,
secret: impl Into<String>,
passphrase: impl Into<String>,
) -> Self {
self.builder_api_key = Some(key.into());
self.builder_secret = Some(secret.into());
self.builder_passphrase = Some(passphrase.into());
self
}
pub fn with_builder_credentials_from_env(self) -> Self {
if let (Ok(key), Ok(secret), Ok(passphrase)) = (
std::env::var("POLY_BUILDER_API_KEY"),
std::env::var("POLY_BUILDER_SECRET"),
std::env::var("POLY_BUILDER_PASSPHRASE"),
) {
self.with_builder_credentials(key, secret, passphrase)
} else {
self
}
}
pub fn has_api_credentials(&self) -> bool {
self.api_key.is_some() && self.api_secret.is_some() && self.api_passphrase.is_some()
}
pub fn has_builder_credentials(&self) -> bool {
self.builder_api_key.is_some()
&& self.builder_secret.is_some()
&& self.builder_passphrase.is_some()
}
pub fn is_authenticated(&self) -> bool {
self.private_key.is_some() || self.has_api_credentials()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn signature_type_parses_gnosis_safe_variants() {
for s in [
"gnosis",
"gnosissafe",
"gnosis_safe",
"safe",
"poly_gnosis_safe",
"2",
"GNOSIS_SAFE",
] {
assert_eq!(
PolymarketSignatureType::from(s),
PolymarketSignatureType::GnosisSafe,
"expected {s:?} → GnosisSafe"
);
}
}
#[test]
fn signature_type_parses_proxy_variants() {
for s in ["proxy", "browser", "poly_proxy", "1"] {
assert_eq!(
PolymarketSignatureType::from(s),
PolymarketSignatureType::Proxy,
"expected {s:?} → Proxy"
);
}
}
#[test]
fn signature_type_defaults_to_eoa() {
for s in ["eoa", "0", "", "nonsense"] {
assert_eq!(
PolymarketSignatureType::from(s),
PolymarketSignatureType::Eoa,
"expected {s:?} → Eoa"
);
}
}
}