Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ if(POLICY CMP0135)
cmake_policy(SET CMP0135 NEW)
endif()

project(polymarket_cpp_client VERSION 3.0.0 LANGUAGES CXX C)
project(polymarket_cpp_client VERSION 4.0.0 LANGUAGES CXX C)

if(PROJECT_IS_TOP_LEVEL)
set(CMAKE_CXX_STANDARD 20)
Expand Down
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@ Tick size and neg-risk metadata are resolved and cached for you. See
| **Trading** | CLOB V2 EIP-712 order signing (EOA, proxy, Safe, `POLY_1271` deposit wallets), limit and market orders, batch posting, cancels, tick-size rounding |
| **Order flow** | Book-walk fill estimates, one-call limit and market orders with post-only, GTD, and worst-price bounds, on-chain settlement waits |
| **Market data** | REST books, prices, midpoints, markets, trades; WebSocket orderbook streaming with reconnect, subscription replay, gap detection, backpressure |
| **Discovery** | Typed `GammaClient` for markets, events, tags, series, sports, teams, search, comments, and profiles |
| **Data API** | Typed `DataClient` for wallet activity, positions, portfolio analytics, market data, and leaderboards |
| **Public streams** | `RtdsStream` for comments, reactions, and prices; `SportsStream` for live game results, with gap and recovery callbacks |
| **Pagination** | `Paginator<T>` and CLOB, Gamma, and Data API pagers with page iteration, bounded collection, resume tokens, and explicit errors |
| **User stream** | Authenticated `UserStream` with typed order/trade events, gap callbacks, and REST reconciliation hooks |
| **On-chain positions** | `PositionClient` split/merge/redeem for CTF and Protocol V2, trading approvals, gasless Safe operations through the Polymarket relayer |
| **Polygon indexing** | JSON-RPC HTTP catch-up + WebSocket subscriptions, persistent `EvmEventIndexer`, UMA and Conditional Tokens event decoders |
Expand All @@ -114,7 +118,7 @@ include(FetchContent)
FetchContent_Declare(
polymarket_client
GIT_REPOSITORY https://github.com/SebastianBoehler/polymarket-cpp-client.git
GIT_TAG v3.0.0 # or any release tag
GIT_TAG v4.0.0 # or any release tag
)
FetchContent_MakeAvailable(polymarket_client)

Expand All @@ -129,13 +133,13 @@ dependencies and headers:

```bash
# macOS arm64 (use polymarket-cpp-client-linux-x64.tar.gz on Linux)
curl -LO https://github.com/SebastianBoehler/polymarket-cpp-client/releases/download/v3.0.0/polymarket-cpp-client-macos-arm64.tar.gz
mkdir -p polymarket-cpp-client-3.0.0
tar -xzf polymarket-cpp-client-macos-arm64.tar.gz -C polymarket-cpp-client-3.0.0
curl -LO https://github.com/SebastianBoehler/polymarket-cpp-client/releases/download/v4.0.0/polymarket-cpp-client-macos-arm64.tar.gz
mkdir -p polymarket-cpp-client-4.0.0
tar -xzf polymarket-cpp-client-macos-arm64.tar.gz -C polymarket-cpp-client-4.0.0
```

```cmake
# cmake -S . -B build -DCMAKE_PREFIX_PATH=/absolute/path/to/polymarket-cpp-client-3.0.0
# cmake -S . -B build -DCMAKE_PREFIX_PATH=/absolute/path/to/polymarket-cpp-client-4.0.0
find_package(polymarket_client REQUIRED)
target_link_libraries(your_target PRIVATE polymarket::client)
```
Expand Down Expand Up @@ -391,6 +395,7 @@ Methodology and how to compare branches: [docs/benchmarks.md](docs/benchmarks.md
| [CLOB V2 migration](docs/clob-v2-migration.md) | V2 order signing and exchange contracts |
| [Benchmarks](docs/benchmarks.md) | Benchmark targets and methodology |
| [Migration guide](docs/migration.md) | Upgrading between major versions |
| [v4.0.0 release notes](docs/releases/v4.0.0.md) | New APIs, compatibility changes, and validation limits |
| [Protocol development](docs/protocol-development.md) | Rules for protocol, signing, and stream lifecycle work |
| [Releasing](docs/releasing.md) | Release process for maintainers |

Expand Down
50 changes: 50 additions & 0 deletions docs/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,56 @@
Rebuild consumers against matching headers and libraries whenever you upgrade.
Release notes for each version live in [`docs/releases/`](releases/).

## v4

The string-based `ClobClient` constructors now accept only chain 137. Code such
as `ClobClient(url, 80002)` throws `std::invalid_argument`; it previously paired
that chain ID with production exchange addresses. For another deployment, pass
an `Environment` containing its endpoints, chain ID, and contract addresses.
Changing only the URL in a string constructor still changes only the production
CLOB host, not the Data API or contracts.

```cpp
#include <polymarket/clob_client.hpp>
#include <polymarket/environment.hpp>
#include <polymarket/position_client.hpp>

const auto env = polymarket::Environment::production();
polymarket::ClobClient client(env);
const auto stream_config = polymarket::Config::for_environment(env);
const auto position_config = polymarket::PositionClientConfig::for_environment(env);
```

For a fork or local chain, copy a preset and replace all endpoints and contracts
that differ before passing it to a client. `Environment::preproduction()` is
not a testnet: it uses Polygon mainnet and production contracts. Orders and
on-chain operations can use real funds, and API credentials are per environment.

Rebuild all consumers and shared plugins against matching v4 headers and
libraries. Public layouts changed, including `ClobClient`, `MarketFetcher`,
`PolymarketContracts`, `HttpClientOptions`, `WebSocketOptions`, `WebSocketStats`,
`Config`, and `SdkError`. Include paths remain `<polymarket/...>` and the CMake
target remains `polymarket::client`. CMake package version checks reject a v3
requirement against v4; update `find_package(polymarket_client 3 ...)` to request
version 4 if you specify a major version.

Review these behavior changes when upgrading:

- Rate-limited reads now retry HTTP 429 up to twice using `Retry-After`, subject
to a five-second maximum delay. Writes are not retried. Use
`set_rate_limit_retry(std::nullopt)` to disable read retries on `ClobClient`.
- Heartbeats no longer contribute to HTTP connection statistics or last-request
metrics. A caller-supplied `tick_size` is checked against a cached minimum
when available; otherwise the server validates it.
- Settlement waits require final transaction hashes for confirmed fills. A
confirmation without hashes triggers REST reconciliation and remains pending
if the hashes are still missing.
- `SdkErrorCode` adds `InsufficientLiquidity`, `Timeout`, and
`TransactionFailed`. Update exhaustive switches.

See [the v4.0.0 release notes](releases/v4.0.0.md) for the new data clients,
pagers, streams, and trading helpers.

## v3

Public headers now live under `polymarket/`. Update includes such as
Expand Down
135 changes: 135 additions & 0 deletions docs/releases/v4.0.0.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# v4.0.0

This release adds typed Gamma and Data API clients, public RTDS and Sports
streams, reusable pagination, and trading setup and order-flow helpers.
It includes all changes since v3.0.0.

## Migration and compatibility

This is a major release because the string-based `ClobClient` constructors now
reject chain IDs other than 137. `ClobClient(url, 80002)` throws instead of
signing against production exchange addresses with a different chain ID.
Use an `Environment` with explicit endpoints and contracts for another
deployment. A string constructor changes only the production CLOB host.

Rebuild consumers and shared plugins against matching v4 headers and libraries:
several public layouts changed, including client, config, transport option,
statistics, contract, and error types. Namespaced headers and the CMake target
`polymarket::client` are unchanged. Update CMake package requirements from major
version 3 to 4 where specified. See the [migration guide](https://github.com/SebastianBoehler/polymarket-cpp-client/blob/v4.0.0/docs/migration.md#v4).

`Environment::production()` and `preproduction()` select endpoints and contracts
together. `Config::for_environment()` and
`PositionClientConfig::for_environment()` configure streams and positions from
the same deployment. Preproduction is not a testnet: it uses Polygon mainnet
and production contracts, so orders and on-chain operations can use real funds.
API credentials are per environment.

## Data and discovery

- `GammaClient` provides typed market and event discovery, lookups by ID, slug,
or URL, tags, series, sports, teams, search, comments, and public profiles.
Market lists skip non-binary markets. Position market resolution now uses
Gamma's keyset endpoint.
- `DataClient` covers trades, wallet activity, positions, portfolio value,
statistics, PnL, user volume, accounting snapshot downloads, holders, open
interest, live event volume, price history, resolutions, and leaderboards.
Data amounts use `double`; rows preserve their raw JSON.
- `Paginator<T>` supports cursor, offset, keyset, and page-numbered APIs through
`next_page()`, bounded collection, range iteration, and resume tokens.
CLOB pagers expose markets, open orders, trades, and position lists. Inspect
`error()` after iteration and `truncated()` when an endpoint's offset cap is
reached. Items fetched before an error are retained.

## Public streams

- `SportsStream` delivers typed live game results, answers server text pings,
and reconnects after 30 seconds without frames.
- `RtdsStream` combines comment, reaction, Binance and Chainlink crypto-price,
Chainlink 30/60-second TWAP, and Pyth equity-price subscriptions. Server
subscriptions are shared, diffed while connected, and replayed on reconnect;
per-subscriber filters run locally. Full-accuracy string prices preserve
decimal precision, including exact scaling of Chainlink's 18-decimal integers.
- Both streams report gaps and recovery. Malformed Sports updates and malformed
RTDS events on supported topics report parser errors and trigger recovery.
RTDS stops further subscriber delivery when a callback stops the stream.
These public feeds do not replay missed events; reconcile application state
through REST when needed.
- `WebSocketOptions` adds configurable text pings, server-ping replies, and an
idle reconnect timeout. Existing CLOB heartbeat defaults are preserved.
- Gamma comment parsing now accepts integer-string `positionSize` values.

RTDS's authenticated v2 price service and `activity` topic are not included.
The official SDKs deprecate the included RTDS price topics in favor of the
authenticated price service.

## Trading and wallet setup

- `PositionClient::get_trading_approvals_state()` reads missing token approvals.
`setup_trading_approvals()` grants only those still missing, using the shared
approval set from `required_trading_approvals()`. Low-level ERC-20 approval,
ERC-1155 operator approval, and ERC-20 transfer helpers are also available.
- `estimate_market_price()` simulates fills from REST or an existing book.
`place_limit_order()` supports GTC/GTD and post-only orders;
`place_market_order()` supports FAK/FOK and worst-price bounds. Book-priced
FOK orders reject insufficient liquidity before signing.
- `get_trade()` and `wait_for_order_fill_settlement()` track terminal fill
status and final transaction hashes. Confirmations without hashes reconcile
through REST and remain pending until final hashes arrive. Earlier MINED or
order-response hashes are not reused as final settlement evidence.
- Rate-limited reads retry HTTP 429 up to twice using `Retry-After`, with a
five-second maximum accepted delay. Writes are never retried automatically.
Rate-limit listeners expose server headers and enforcement warnings.
- `SdkErrorCode` adds `InsufficientLiquidity`, `Timeout`, and
`TransactionFailed`; update exhaustive switches.

EOAs pay Polygon gas. Safe operations use the relayer and require
`RELAYER_API_KEY`. Safe batches are atomic; EOA batches can complete partially.
Approval setup grants maximum ERC-20 allowances and ERC-1155 operator access
to the configured contracts, including the perps deposit spender. That approval
does not add perps trading support. Position operations still support EOA and
Gnosis Safe wallets, not `POLY_PROXY`, `POLY_1271`, or combo positions. See the
[position guide](https://github.com/SebastianBoehler/polymarket-cpp-client/blob/v4.0.0/docs/position-operations.md) and [order-flow guide](https://github.com/SebastianBoehler/polymarket-cpp-client/blob/v4.0.0/docs/order-flow.md).

## Networking and request behavior

- REST and WebSocket connections support HTTP/HTTPS/SOCKS proxies and interface
binding through `set_default_network_route()` or per-client options.
Configured routes fail closed. Geoblock checks can reuse an HTTP client.
- HTTP responses can be compressed. Book responses seed tick-size and neg-risk
caches; off-grid prices invalidate only the tick cache. Market discovery reuses
Gamma clients. These changes remove redundant requests and connection setup.
- Orderbook parsing and signing avoid unnecessary copies and allocations.
HTTP heartbeats no longer affect connection statistics or last-request
metrics. Explicit tick sizes use cached minimum validation when available;
otherwise the server validates them.

See the [networking guide](https://github.com/SebastianBoehler/polymarket-cpp-client/blob/v4.0.0/docs/networking.md) for route configuration and limits.

## Validation and evidence limits

The offline suite covers local HTTP/RPC/relayer fixtures, pagination, parsing,
stream recovery, callback shutdown, and installed-package consumers. ASan/UBSan
and libFuzzer checks cover REST and WebSocket parsers. Release publication is
gated on Linux x86-64 and macOS arm64 package builds and offline tests.

Local release preparation passed 84/84 offline tests on macOS arm64 in Release,
including the installed-package consumer and both fuzz corpus replays. A
separate installed-package consumer linked the new clients and streams,
verified version 4.0.0, and checked the chain-80002 rejection without network
requests. The migration example compiled against the release headers.

Contributors reported read-only live checks for production and preproduction
CLOB reads, book estimates, routed streams, Gamma and Data API responses,
Sports updates, and RTDS comments and crypto prices. Equity stream updates and
history, removed comments, and Sports finish timestamps have fixture coverage
only. The preproduction Gamma, Data API, and relayer were not validated live.
Order placement and settlement helpers have local fixture coverage; release
validation does not place orders or move funds. An approval setup transaction
was separately reported by the contributor, not executed by release CI.

Thanks to Bill Luo (@yluoc) for the trading approvals, environment support,
rate-limit handling, order-flow helpers, parsers, pagination, data clients,
and public streams.

[Full changes](https://github.com/SebastianBoehler/polymarket-cpp-client/compare/v3.0.0...v4.0.0)
4 changes: 2 additions & 2 deletions include/polymarket/version.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#pragma once

#define POLYMARKET_CLIENT_VERSION_MAJOR 3
#define POLYMARKET_CLIENT_VERSION_MAJOR 4
#define POLYMARKET_CLIENT_VERSION_MINOR 0
#define POLYMARKET_CLIENT_VERSION_PATCH 0
#define POLYMARKET_CLIENT_VERSION "3.0.0"
#define POLYMARKET_CLIENT_VERSION "4.0.0"

namespace polymarket
{
Expand Down
Loading