polynode
Rust SDK for the PolyNode real-time Polymarket API.
Stream settlements, trades, positions, deposits, oracle events, orderbook updates, and more through a single WebSocket connection. All events enriched with full market metadata.
New in v0.13.11: Rust V2 trading now separates user CLOB credentials, public builder attribution, and relayer auth. The default path uses PolyNode's public builder code plus PolyNode managed relay with a per-user relayer key; users can still bring their own builder code, direct Polymarket builder credentials, or direct RPC submission for Safe/proxy calls.
New in v0.13.10: Published docs now include explicit Rust examples for both supported V2 wallet identities: existing Safe users (POLY_GNOSIS_SAFE) and new deposit-wallet users (POLY_1271).
New in v0.13.9: Rust V2 trading keeps Safe and deposit-wallet identities separate: pass an explicit signature_type plus funder_address to route existing Safe users through POLY_GNOSIS_SAFE, while new deposit-wallet users continue through POLY_1271. Safe V2 onboarding can now relay pUSD/CTF approvals, and stored credentials are reused without silently flipping wallet type.
New in v0.13.8: Rust deposit-wallet V2 trading now self-heals deployed-wallet onboarding, includes USDC.e collateral-onramp approval, uses the deposit wallet as both order maker and signer for POLY_1271, wraps available USDC.e into pUSD before buy orders, and matches Polymarket's current V2 POLY_1271 order body and wrapped signature format.
New in v0.12: V2 order flow — place orders on the Polymarket V2 CLOB with pUSD collateral and builder attribution. See src/trading/V2_ORDER_FLOW.md for the full reference.
In v0.5: Local Cache — SQLite-backed local storage. Backfill wallet history in seconds, query trades and positions instantly with zero API calls.
Install
[]
= "0.13.11"
= { = "1", = ["rt", "macros"] }
# For local cache (optional):
# polynode = { version = "0.13.11", features = ["cache"] }
Quick Start
use PolyNodeClient;
async
Rust V2 Trading Wallet Modes
Polymarket V2 supports two smart-wallet identities. They are not interchangeable:
- Existing Safe users:
SignatureType::PolyGnosisSafe, with the Safe address asfunder_address. - New deposit-wallet users:
SignatureType::Poly1271, with the deposit wallet address asfunder_address.
Pass both values explicitly whenever you know the user's Polymarket wallet type. This prevents the SDK from deriving a different wallet and sending orders with a maker address that the CLOB does not allow.
The SDK also separates three credential paths:
- User CLOB API credentials are created or loaded by
ensure_ready()and always authenticate order placement, cancels, open orders, and balance/allowance checks. - V2 builder codes are public bytes32 attribution values.
TraderConfig::default()uses PolyNode's builder code; users can override it withTraderConfig.builder_codeor per order withOrderParams.builder. - Relayer auth is used only for gasless smart-wallet calls such as deploy, approve, wrap, and unwrap.
RelayerMode::Autouses PolyNode managed relay whenpolynode_keyandcosigner_urlare configured, then falls back to direct builder credentials when supplied.RelayerMode::DirectRpcbypasses the relayer for Safe/proxy calls and pays gas from the signer.
Existing Safe user:
use ;
let signer = from_hex?;
let mut trader = new?;
trader.ensure_ready.await?;
Deposit-wallet user:
use ;
let signer = from_hex?;
let deposit_wallet = format!;
let mut trader = new?;
trader.ensure_ready.await?;
Both paths use pUSD on V2. The SDK can wrap available USDC.e into pUSD before BUY orders when the configured wallet has the required onramp approval and a relayer path is configured.
Bring your own builder attribution while keeping PolyNode managed relay:
use ;
let mut trader = new?;
Use direct Polymarket builder credentials for relayer auth instead:
use ;
let mut trader = new?;
Bypass the relayer for Safe/proxy calls:
use ;
let mut trader = new?;
DirectRpc signs Safe execTransaction calls and broadcasts through rpc_url. It requires a signer with TradingSigner::sign_hash support, such as PrivateKeySigner; the built-in PrivySigner does not currently sign raw transactions. It is not used for deposit-wallet factory calls.
REST API
// System
client.healthz.await?;
client.status.await?;
client.create_key.await?;
// Markets
client.markets.await?;
client.market.await?;
client.market_by_slug.await?;
client.market_by_condition.await?;
client.list_markets.await?;
client.search.await?;
// Pricing
client.candles.await?;
client.stats.await?;
// Settlements
client.recent_settlements.await?;
client.token_settlements.await?;
client.wallet_settlements.await?;
// Wallets
client.wallet.await?;
// RPC (rpc.polynode.dev)
client.rpc_call.await?;
WebSocket Streaming
use ;
use WsMessage;
let mut stream = client.stream.await?;
stream.subscribe.await?;
while let Some = stream.next.await
Subscription Types
Settlements // pending + confirmed settlements
Trades // all trade activity
Prices // price-moving events
Blocks // new Polygon blocks
Wallets // all wallet activity
Markets // all market activity
LargeTrades // $1K+ trades
Oracle // UMA resolution events
Chainlink // real-time price feeds
Subscription Filters
new
.wallets
.tokens
.slugs
.condition_ids
.side
.status
.min_size
.max_size
.event_types
.snapshot_count
.feeds
Orderbook Streaming
use ;
let mut stream = client.orderbook_stream.await?;
stream.subscribe.await?;
let mut book = new;
while let Some = stream.next.await
// Query local state
let best_bid = book.best_bid;
let best_ask = book.best_ask;
let spread = book.spread;
OrderbookEngine
Higher-level orderbook client. One connection, shared state, filtered views for different parts of your app.
use ;
let engine = connect.await?;
// Subscribe with token IDs, slugs, or condition IDs
engine.subscribe.await?;
// Query computed values from local state
engine.midpoint.await; // Some(0.465)
engine.spread.await; // Some(0.01)
engine.best_bid.await; // Some(OrderbookLevel { price: "0.46", size: "226.29" })
engine.book.await; // Some((bids, asks))
// Create filtered views for different components
let mut view = engine.view;
view.midpoint.await; // reads from shared state
// Receive only this view's updates
while let Some = view.next.await
engine.close.await?;
Zlib compression is enabled by default (~50% bandwidth savings). All connections auto-reconnect with exponential backoff.
Local Cache
Store trades and positions in a local SQLite database. Backfills recent history on startup, streams live updates, and serves all queries locally with zero API calls.
Enable the cache feature in your Cargo.toml:
= { = "0.13.11", = ["cache"] }
use ;
use Arc;
let client = new;
let mut cache = builder
.db_path
.watchlist_path
.on_backfill_progress
.build?;
cache.start.await?;
// Query locally — instant, no API calls
let trades = cache.wallet_trades?;
let positions = cache.wallet_positions?;
let stats = cache.stats?;
// Add wallets at runtime
use EntityType;
cache.add_to_watchlist?;
cache.stop.await?;
Watchlist (polynode.watch.json):
Backfill timing: 1 request per wallet at 1 req/s. 10 wallets = 10 seconds. See full documentation.
Configuration
let client = builder
.base_url
.ws_url
.ob_url
.rpc_url
.timeout
.build?;
Error Handling
use Error;
match client.market.await
Links
License
MIT