Skip to content

feat: add SOCKS5/HTTP proxy support#21

Closed
croll83 wants to merge 8 commits intoPolymarket:mainfrom
croll83:feat/socks-proxy-support
Closed

feat: add SOCKS5/HTTP proxy support#21
croll83 wants to merge 8 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
Moderate risk because it changes network/proxy behavior by setting proxy-related environment variables and enables new reqwest features, which can affect all outbound HTTP requests and dependency resolution.

Overview
Adds first-class proxy support for the CLI by introducing a global --proxy flag with POLYMARKET_PROXY/config fallback and wiring it into the process environment so SDK HTTP calls can route through SOCKS5/HTTP proxies.

Updates dependencies to include reqwest with the socks feature and switches polymarket-client-sdk to a local patched dependency (including new SDK metadata/CI files), which changes how the SDK is sourced and built in this repo.

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

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

…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
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

croll83 and others added 3 commits March 2, 2026 09:40
The Polymarket API returns `"endDate": ""` for markets without an
expiry, causing serde deserialization to crash with "premature end of
input". Vendor polymarket-client-sdk v0.4.2 locally and change
`Position.end_date` from `NaiveDate` to `Option<NaiveDate>` with
`NoneAsEmptyString` (pattern already used elsewhere in the SDK).

Fixes: data positions crash for users holding markets without end dates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

rust_decimal_macros = "1"

[patch.crates-io]
polymarket-client-sdk = { path = "polymarket-client-sdk" }
Copy link

Choose a reason for hiding this comment

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

Vendored SDK as local path patch committed

High Severity

The [patch.crates-io] section overrides polymarket-client-sdk with a local path (polymarket-client-sdk), and the entire SDK source tree is vendored into the repository. This means the project no longer pulls the published crate from crates.io and instead depends on a local copy that could drift from upstream. This appears to be development scaffolding — the PR's stated goal is only to add proxy support, not to vendor the SDK. This will break builds for anyone who clones the repo without the vendored directory and complicates future SDK updates.

Fix in Cursor Fix in Web

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.

Reqwest socks feature missing from direct dependency

High Severity

The reqwest dependency is added with the socks feature, but this is a separate reqwest 0.13 crate from the one used by alloy (which depends on reqwest 0.12). Cargo feature unification only works within the same version of a crate. Since alloy-transport-http and alloy-provider depend on reqwest 0.12, the socks feature enabled on reqwest 0.13 won't propagate to reqwest 0.12. The SOCKS5 proxy set via env vars (HTTPS_PROXY) will likely fail for alloy's HTTP transport because its reqwest 0.12 client wasn't compiled with socks support.

Fix in Cursor Fix in Web

@croll83
Copy link
Author

croll83 commented Mar 6, 2026

Closing — scope has diverged beyond the original proxy feature. Will maintain these changes in my fork. Thanks for the review feedback.

@croll83 croll83 closed this Mar 6, 2026
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