SettlementExposureGuard tracks how much pUSD is committed in markets that share the same UMA resolution window and blocks or downsizes new orders that would push the concurrent settlement exposure above the configured ceiling. It prevents the user from having more equity at risk in a single 2-hour UMA settlement window than they can afford to lose if all markets in that window resolve adversely.
Every OrderIntent — caps simultaneous settlement resolution risk by limiting how much equity is locked in markets that could resolve in the same UMA oracle window
Default mode
planned
User-visible
summary-only
Developer owner
Polytraders core — Risk pod
Operational profile
Modes supported
quarantine
2. Purpose
SettlementExposureGuard tracks how much pUSD is committed in markets that share the same UMA resolution window and blocks or downsizes new orders that would push the concurrent settlement exposure above the configured ceiling. It prevents the user from having more equity at risk in a single 2-hour UMA settlement window than they can afford to lose if all markets in that window resolve adversely.
3. Why This Bot Matters
Multiple markets resolving in same UMA window
Markets resolving in the same 2-hour UMA window create a concentration of settlement risk; an adverse outcome across all of them results in simultaneous losses the user did not anticipate.
No cap on concurrent settlement exposure
Without a settlement window cap, strategies can inadvertently concentrate the majority of the portfolio in a single 2-hour settlement batch.
4. Required Polymarket Inputs
Input
Source
Required?
Use
Market resolution end_date and UMA challenge window metadata
gamma
Yes
Group open positions by their UMA resolution window (2-hour buckets) to compute concurrent settlement exposure.
Open position notional by market
clob_public
Yes
Sum the pUSD notional for all positions in each UMA window bucket.
Maximum pUSD allowed to resolve in a single UMA settlement window (default 2 hours).
uma_window_hours
2.0
None
None
Duration in hours of the UMA settlement window used for grouping positions. Matches the UMA optimistic oracle 2-hour challenge period.
warn_pct
0.8
None
None
Fraction of max_concurrent_settlement_usd at which a WARN annotation is emitted without blocking.
7. Detailed Parameter Instructions
max_concurrent_settlement_usd
What it means
Maximum pUSD allowed to resolve in a single UMA settlement window (default 2 hours).
Default
{ "max_concurrent_settlement_usd": 3000 }
Why this default matters
3000 pUSD per window ensures that a worst-case adverse resolution of all markets in the window cannot exceed a manageable loss fraction of a typical 10 000 pUSD portfolio.
Threshold logic
Condition
Action
window_exposure + intent.size_usd <= 2400
APPROVE
2400 < total <= 3000
WARN — SETTLEMENT_EXPOSURE_APPROACHING
total > 3000
RESHAPE or HARD_REJECT — SETTLEMENT_EXPOSURE_EXCEEDED
Developer check
if (windowExposure + intent.size_usd > params.max_concurrent_settlement_usd) return reshape_or_reject('SETTLEMENT_EXPOSURE_EXCEEDED');
User-facing English
Your exposure in this settlement window has reached the limit.
uma_window_hours
What it means
Duration in hours of the UMA settlement window used for grouping positions. Matches the UMA optimistic oracle 2-hour challenge period.
Default
{ "uma_window_hours": 2.0 }
Why this default matters
2 hours is the canonical UMA challenge window; grouping by this interval correctly identifies markets that will compete for the same resolution event slot.
Your order was reduced because your exposure in this settlement window has reached its limit. Adding more would concentrate too much risk in a single resolution event.
Order blocked — window fully utilised
You have reached the maximum exposure in this settlement window. Please wait for some of those markets to resolve before placing new orders.
18. Failure-Mode Block
main_failure_mode
Approving an order because the position cache is stale and does not include recently placed orders in the same UMA window, underestimating window exposure.
false_positive_risk
Blocking an order because a position in the same window has already been closed but the cache has not been refreshed.
false_negative_risk
Two concurrent intents approved simultaneously before either updates the position cache, both contributing to the same window bucket.
safe_fallback
If Gamma market metadata or position data is unavailable, HARD_REJECT with SETTLEMENT_EXPOSURE_DATA_UNAVAILABLE. Never approve on missing data.
required_dependencies
Gamma API (market end_date), CLOB position data, Settlement exposure config, KillSwitch active flag
19. Failure-Injection Recipes
Scenario
How to inject
Expected behaviour
Recovery
GAMMA_UNAVAILABLE
Return 503 from Gamma API
Returns to normal after Gamma API is reachable.
WINDOW_CAP_REACHED
Load positions to fill bucket_key to 3000 pUSD, submit any intent for the same bucket
Returns to APPROVE after positions in the bucket reduce below ceiling.
CONCURRENT_INTENTS
Submit two intents simultaneously for the same bucket_key
Immediate — second intent is evaluated after first updates the bucket exposure.
20. State & Persistence
Cold-start recovery
Position cache rebuilt from CLOB on cold start. Gamma cache populated on first market lookup.
21. Concurrency & Idempotency
Aspect
Specification
Execution model
single-threaded event loop
Max in-flight
200
Idempotency key
intent_id
Per-call timeout (ms)
100
Backpressure strategy
drop newest
Locking / mutual exclusion
per-bucket optimistic lock to prevent concurrent over-allocation in same window
HARD_REJECT(SETTLEMENT_EXPOSURE_DATA_UNAVAILABLE) if Gamma unavailable.
CLOB API (positions)
https://clob.polymarket.com
99.95% / 200ms p99
HARD_REJECT(SETTLEMENT_EXPOSURE_DATA_UNAVAILABLE) if position data unavailable.
23. Security Surfaces
Abuse vectors considered
Submitting concurrent intents for the same UMA window bucket to bypass per-intent idempotency
Selecting markets with staggered end_dates that fall just outside the window bucket to accumulate higher effective exposure
Mitigations
Per-bucket optimistic lock ensures at most one intent is processed at a time per bucket
Market end_date is fetched from Gamma at evaluation time, not trusted from the intent payload
24. Polymarket V2 Compatibility
Aspect
Value
CLOB version
v2
Collateral asset
pUSD
EIP-712 Exchange domain version
2
Aware of builderCode field
no
Aware of negative-risk markets
yes
Multi-chain ready
no
SDK used
py-clob-client-v2
Settlement contract
CTFExchangeV2
Notes
Settlement window grouping uses UMA optimistic oracle 2-hour challenge period per V2 protocol. NegRisk markets are included in window calculations using their Gamma end_date.
25. Versioning & Migration
Field
Value
spec
2.0.0
implementation
0.1.0
schema
2
released
None
planned_release
Q4-2026
Migration history
Date
From
To
Reason
Action taken
2026-04-28
n/a
v2-spec
Spec drafted post-CLOB-V2 cutover; bot not yet implemented
Designed against V2 schema (pUSD, builder codes, V2 EIP-712 domain)
26. Acceptance Tests
Unit Tests
Test
Setup
Expected result
Approve when window exposure within warning threshold
Multiple positions in same UMA bucket correctly summed
Window exposure reflects all open positions with matching bucket_key
KillSwitch bypasses settlement check
HARD_REJECT(KILL_SWITCH_ACTIVE) without reading Gamma or positions
Property Tests
Property
Required behaviour
Total window exposure never exceeds max_concurrent_settlement_usd after APPROVE
Always true
Reshape size is strictly <= original intent size_usd
Always true
27. Operational Runbook
SettlementExposureGuard incidents typically involve a strategy concentrating orders in a single UMA window. Verify the bucket distribution in Grafana before adjusting the ceiling.
On-call actions
Alert
First step
Diagnosis
Mitigation
Escalate to
SettlementExposureGuardWindowNearCap
Check window_exposure_usd gauge; identify which bucket is near cap. Confirm whether this is a genuine concentration or a stale position cache.
Risk pod lead if genuine concentration confirmed.
SettlementExposureGuardDataUnavailable
Check Gamma API and CLOB positions endpoint; confirm connectivity.
Infra on-call if either service is down > 2 minutes.
Manual overrides
polytraders risk refresh-positions --user-id <id> — After a known CLOB sync delay causing stale position data.
Healthcheck
GET /internal/health/settlementexposureguard → green: Gamma cache populated, position cache age < 15s, no buckets within 20% of ceiling; red: Gamma or CLOB unavailable, position cache age > 60s
28. Promotion Gates
A bot does not advance to the next readiness state until every gate below is green. Gates are observable from production data — no subjective sign-off.
Promote to Shadow
Gate
How measured
Threshold
Unit tests pass for reshape and reject window scenarios
CI test run
100% pass
Promote to Limited live
Gate
How measured
Threshold
Window bucket grouping verified against live Gamma end_date values over 48h
Manual spot-check of bucket_key assignment
100% correct bucketing
Promote to General live
Gate
How measured
Threshold
Zero DATA_UNAVAILABLE rejections during normal hours over 7 days
SettlementExposureGuardDataUnavailable alert history