Skip to content

feat: add SOCKS5/HTTP proxy support#21

Open
croll83 wants to merge 5 commits intoPolymarket:mainfrom
croll83:feat/socks-proxy-support
Open

feat: add SOCKS5/HTTP proxy support#21
croll83 wants to merge 5 commits intoPolymarket:mainfrom
croll83:feat/socks-proxy-support

Conversation

@croll83
Copy link

@croll83 croll83 commented Feb 25, 2026

Summary

  • Adds --proxy global CLI flag for SOCKS5/HTTP proxy (e.g., --proxy socks5://127.0.0.1:1080)
  • Reads POLYMARKET_PROXY env var as fallback when flag is not provided
  • Enables reqwest socks feature for SOCKS5 protocol support

Motivation

The Polymarket CLOB geoblocks certain regions. Users behind VPNs or corporate proxies need a way to route CLI traffic through a SOCKS5 or HTTP proxy. Currently reqwest is compiled without socks support, so standard proxy env vars (ALL_PROXY, HTTPS_PROXY) don't work with SOCKS5 URLs.

Changes

  • Cargo.toml: Added reqwest with socks feature (Cargo unifies features across dependency tree)
  • src/main.rs: Added --proxy global flag + POLYMARKET_PROXY env var resolution, sets HTTPS_PROXY/HTTP_PROXY before client initialization

Usage

# Via flag
polymarket --proxy socks5://127.0.0.1:1080 markets search "Bitcoin"

# Via env var
POLYMARKET_PROXY=socks5://127.0.0.1:1080 polymarket markets search "Bitcoin"

# HTTP proxy also works
polymarket --proxy http://proxy.example.com:8080 clob balance

Note

Medium Risk
Changes process-wide proxy environment handling and early startup/runtime initialization, which can affect all outbound networking behavior if misconfigured; scope is otherwise contained to CLI/config plumbing and output renames.

Overview
Adds SOCKS5/HTTP proxy support via a new global --proxy flag plus POLYMARKET_PROXY/config-file fallback, and enables reqwest’s socks feature to make SOCKS URLs work.

Moves proxy resolution to happen before the Tokio runtime starts and sets HTTP_PROXY/HTTPS_PROXY (with NO_PROXY exclusions for Polygon RPC) so only API traffic is proxied; also extends config schema to persist an optional proxy value and avoids treating an empty stored private_key as configured.

Separately, wallet/setup output is generalized from “proxy wallet” to “trading wallet” by deriving the address based on signature type (proxy vs gnosis-safe vs EOA) and renaming JSON fields accordingly.

Written by Cursor Bugbot for commit 489d83e. This will update automatically on new commits. Configure here.

"dirs",
"polymarket-client-sdk",
"predicates",
"reqwest 0.13.2",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cargo.lock missing tokio-socks, SOCKS feature not compiled

High Severity

Cargo.toml declares reqwest with features = ["socks"], which requires the tokio-socks optional dependency. However, tokio-socks is completely absent from Cargo.lock — searching for "socks" yields zero results. The lock file appears to have been manually edited (only adding the "reqwest 0.13.2" line) rather than regenerated by cargo. This means the socks feature isn't actually compiled in, so SOCKS5 proxy support silently doesn't work.

Additional Locations (1)

Fix in Cursor Fix in Web

Address review feedback:
- Move from #[tokio::main] to sync fn main() so set_var runs before
  any worker threads are spawned (eliminates UB on Rust 2024 edition)
- Add NO_PROXY=polygon.drpc.org,drpc.org to exclude Polygon RPC from
  SOCKS5 proxying — alloy depends on reqwest 0.12 which lacks socks
  support and would fail if HTTP(S)_PROXY points to a socks5:// URL
- Build tokio runtime manually with Builder::new_multi_thread()

Tested: CLOB calls route through SOCKS5, approve check (alloy RPC)
bypasses proxy and queries Polygon directly.
@croll83
Copy link
Author

croll83 commented Feb 25, 2026

all valid points!

The third commit (e690e5f) addresses all 3 Cursor bot review issues:

Issue Fix
set_var after tokio spawns threads (UB) Converted to sync fn main() — env vars set before Builder::new_multi_thread().build()
tokio-socks missing from Cargo.lock Resolved automatically on build (reqwest socks feature pulls it in)
Global SOCKS5 breaks alloy reqwest 0.12 Added NO_PROXY=polygon.drpc.org,drpc.org to exclude Polygon RPC from proxying

Verified on server:

  • polymarket status → API OK (through SOCKS5 proxy)
  • polymarket clob balance → $5.49 (CLOB calls go through proxy)
  • polymarket approve check → All contracts approved (alloy RPC bypasses proxy via NO_PROXY)

Address cursor bot review:
- save_wallet now reads existing proxy from config before overwriting,
  preventing silent loss of user-configured proxy URL
- resolve_key treats empty string from config as None, so callers get
  the helpful "No wallet configured" message instead of a confusing
  "Invalid private key" error when private_key is absent from config
unsafe {
std::env::set_var("HTTPS_PROXY", url);
std::env::set_var("HTTP_PROXY", url);
std::env::set_var("NO_PROXY", "polygon.drpc.org,drpc.org");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NO_PROXY overwrites existing user environment variable values

Medium Severity

Setting NO_PROXY to a hardcoded value unconditionally replaces any existing NO_PROXY entries the user already has in their environment. Since this feature specifically targets corporate/VPN users — who commonly have NO_PROXY configured for internal services — this overwrites those entries within the CLI process. The existing entries need to be preserved by reading the current NO_PROXY value and appending polygon.drpc.org,drpc.org to it rather than replacing it.

Fix in Cursor Fix in Web

/// Priority: CLI flag > env var > config file.
pub fn resolve_proxy(cli_flag: Option<&str>) -> Option<String> {
if let Some(url) = cli_flag {
return Some(url.to_string());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty proxy string not filtered from CLI flag

Low Severity

resolve_proxy filters empty strings for the POLYMARKET_PROXY env var path (via !url.is_empty()) but does not apply the same check to the CLI flag path or the config file path. An empty --proxy "" value or an empty proxy string in the config file would result in setting HTTPS_PROXY and HTTP_PROXY to empty strings, likely causing confusing request failures.

Fix in Cursor Fix in Web

…pport)

wallet show/create/import now use the configured signature_type
to derive the correct trading wallet address:
- "proxy" → EIP-1167 minimal proxy (Magic/email wallets)
- "gnosis-safe" → Gnosis Safe 1-of-1 (browser/MetaMask wallets)
- "eoa" → no derived wallet, use EOA directly

Previously all wallet commands hardcoded derive_proxy_wallet(),
ignoring the signature_type setting entirely. This caused the CLI
to show the wrong deposit address when using gnosis-safe mode
(which is what polymarket.com creates for browser wallet users).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@croll83 croll83 force-pushed the feat/socks-proxy-support branch from 586b4ba to 489d83e Compare February 25, 2026 23:56
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

tabled = "0.17"
rust_decimal = "1"
anyhow = "1"
reqwest = { version = "0.13", features = ["socks"] }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cargo.lock missing tokio-socks breaks SOCKS5 proxy support

High Severity

The Cargo.toml adds reqwest with features = ["socks"], but the committed Cargo.lock does not contain tokio-socks anywhere — the required transitive dependency for SOCKS5 support. The reqwest 0.13.2 entry in the lockfile lists no socks-related dependencies. This means builds using cargo install --locked or CI with --locked will compile reqwest without actual SOCKS5 support, silently making the PR's core feature non-functional at runtime.

Additional Locations (1)

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant