Chapter 36 of 36
Die Kurzfassung
On April 28, 2026, Polymarket migrated its settlement collateral on Polygon from USDC.e (the bridged USDC token, contract 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174) to pUSD, a Polymarket-issued stablecoin redeemable 1:1 for native USDC. Web-app traders did nothing - balances and positions auto-converted at the snapshot block. API and bot operators must update: the collateral asset address inside every CLOB order signature changed, old orders signed against USDC.e were canceled, and py-clob-client 0.40 or newer is required. This guide walks through the exact code, contract, and approval changes needed to keep a bot running through and after the cutover.
Part 1: Three Stablecoins, One Polygon
Before the migration, three USD stablecoins existed in Polymarket's orbit on Polygon. Knowing the difference is the first step to understanding why Polymarket changed venues.
| Token | Issuer | Contract on Polygon | Reserve type |
|---|---|---|---|
| USDC.e | Polygon PoS bridge | 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174 | Bridged from Ethereum mainnet |
| USDC (native) | Circle | 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 | Native, issued directly on Polygon |
| pUSD | Polymarket Treasury | See docs.polymarket.com/pusd | 1:1 backed by native USDC, monthly attestation |
Polymarket originally chose USDC.e because it was the dominant USDC variant on Polygon at launch in 2020. Circle later issued native USDC directly on Polygon and signaled the eventual deprecation of the bridged variant. Continuing to settle every market in USDC.e exposed Polymarket to the long-tail risk of a sudden bridge wind-down. Migrating to a Polymarket-controlled stablecoin solves that and unlocks future product features (e.g., perps margin, vault deposits, cross-chain receipts) that share the same unit of account.
Part 2: What pUSD Is (and Isn't)
pUSD is a standard ERC-20 token on Polygon (chain id 137) with 6 decimals, the same precision as USDC. It is mintable only by the Polymarket Treasury contract and is redeemable 1:1 for native USDC at any time, with no fee on the conversion (network gas still applies). The reserve backing pUSD is held in segregated accounts and reported monthly with a third-party attestation.
pUSD is not an algorithmic stablecoin, is not over-collateralized with crypto, and is not yield-bearing. If you hold pUSD outside Polymarket, you should think of it as a Polymarket-issued IOU for native USDC - useful inside the platform, redeemable on demand, but with no benefit to holding long-term in an external wallet.
docs.polymarket.com/pusd-audit on a monthly cadence. Verify both before holding large balances long-term.Part 3: What Web-App Traders Saw
If you only trade through polymarket.com, the migration was invisible. At the snapshot block on April 28, 2026:
- Every USDC.e balance held in a Polymarket proxy wallet was atomically converted to pUSD at 1:1.
- Open positions kept the same dollar value, the same outcome odds, and the same expiry. Conditional token IDs did not change.
- Resting orders denominated in USDC.e were canceled at the snapshot. New orders post-migration sign against pUSD automatically.
- Withdrawals to external wallets switched from sending USDC.e to sending native USDC (or, on request, raw pUSD - most users never need to).
No signatures, transactions, or settings changes were required. Resting limit orders that mattered to you should be re-placed manually after the migration; the cancellation was a one-time event.
Part 4: API and Bot Operators - Critical Changes
This is the part that will break a bot if you don't act.
0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174). Post-migration, it is pUSD. An order signed against the old address will fail signature verification at CLOB and return an "invalid maker asset" or "signature mismatch" error.Upgrade py-clob-client
Polymarket published py-clob-client 0.40.0 two weeks before the cutover with full pUSD support. The 0.34.x line was retired the day after the migration.
# Bump to a pUSD-aware release
pip install --upgrade "py-clob-client>=0.40.0"
# Verify the wired collateral asset
python -c "from py_clob_client.constants import POLYGON; \
print('pUSD address:', POLYGON.get('collateral'))"
The new SDK pulls the collateral address from chain configuration at startup, so you do not need to hard-code anything. If you forked or pinned an older version, the safest move is to delete the lockfile, reinstall with the latest constants module, and re-run your test suite.
Re-approve allowances
Your Polymarket proxy wallet needs an ERC-20 allowance from your trading account → CTF Exchange contract for the pUSD token. The old allowance for USDC.e is still on-chain but completely useless: CLOB will not consume it. Without a fresh pUSD allowance, every order returns "INSUFFICIENT_ALLOWANCE".
from py_clob_client.client import ClobClient
client = ClobClient(
host="https://clob.polymarket.com",
chain_id=137,
key=os.environ["POLY_PRIVATE_KEY"],
funder=os.environ["POLY_FUNDER"],
signature_type=1, # POLY_PROXY for Magic-link accounts
)
client.set_api_creds(client.create_or_derive_api_creds())
# One-time: approve pUSD for the CTF Exchange contract
# (Helper added in py-clob-client 0.40)
client.update_balance_allowance(asset_type="COLLATERAL")
Refresh API credentials
Existing API keys continue to work, but if you derived credentials before April 1 you should rotate them as a precaution: the L1 ECDSA signature now binds to a domain that includes the new collateral address. The simplest path:
creds = client.create_or_derive_api_creds() # idempotent re-derive
client.set_api_creds(creds)
# Persist to your .env
print(creds.api_key, creds.api_secret, creds.api_passphrase)
Part 5: Verifying Your Bot Post-Migration
Run this minimal smoke test before letting any sizing logic loose on real money:
# 1. Confirm pUSD balance on the proxy wallet
from py_clob_client.client import ClobClient
client = ClobClient(...) # as above
balance = client.get_balance_allowance(params={"asset_type": "COLLATERAL"})
print("pUSD balance (raw):", balance["balance"])
print("Allowance to exchange:", balance["allowance"])
# 2. Place a $1 limit order well off the touch
from py_clob_client.clob_types import OrderArgs
order = client.create_order(OrderArgs(
token_id=test_token_id,
price=0.05, # nowhere near the market
size=20, # $1 notional at $0.05
side="BUY",
))
resp = client.post_order(order)
print(resp)
# 3. Cancel and confirm
client.cancel(order_id=resp["orderID"])
If all three calls succeed, your wiring is good: the SDK signed against pUSD, the allowance is recognized, and the order ledger is consistent. Scale back up gradually.
Part 6: Common Errors and Fixes
| Error or symptom | Cause | Fix |
|---|---|---|
signature verification failed | Order signed against USDC.e EIP-712 domain | Upgrade py-clob-client to 0.40+; reload constants module |
INSUFFICIENT_ALLOWANCE on every order | No pUSD allowance from your proxy to CTF Exchange | Run update_balance_allowance(asset_type="COLLATERAL") once |
invalid maker asset | Hard-coded USDC.e address still in your config | Replace any hard-coded collateral address with SDK constant |
| Wallet shows USDC.e balance > 0 after migration | "Dust" tokens left over from a third-party transfer | Bridge USDC.e back to native USDC on Circle's CCTP, or leave it |
| WebSocket reconnect produces empty book | Old subscription used a stale market state from before snapshot | Drop local cache, re-fetch REST book, then resubscribe |
| Withdraw to external wallet shows pUSD instead of USDC | You selected "pUSD" instead of "USDC" in the withdraw modal | Pick "USDC" - the bridge converts pUSD → native USDC at 1:1 |
Part 7: Conditional Tokens, Order IDs, and Other Things That Did Not Change
To keep refactor scope honest, here is the list of identifiers that are stable across the migration:
- Conditional Token contract (CTF): identical address. Your YES / NO ERC-1155 positions are untouched.
- condition_id and question_id: deterministic from market parameters; not affected by collateral swap.
- token_id (outcome): derived from condition_id + outcome index; unchanged.
- Polymarket proxy wallet address: same address; same Gnosis Safe-style code.
- API key, API secret, API passphrase: still valid (recommend rotating; not required).
- WebSocket schemas: identical; new
assetfield reads "pUSD" instead of "USDC.e" in fill events. - Gamma and Data APIs: unauthenticated, unchanged. They never referenced the collateral token directly.
Part 8: Tax and Bookkeeping Implications
For most jurisdictions the auto-conversion of USDC.e to pUSD is a like-kind swap of USD-pegged stablecoins at 1:1 and produces no taxable event. Your cost basis and holding period carry across.
That said, two book-keeping items deserve attention:
- Update your ledger schema. Any tax tool, SQLite ledger, or accountant export that filters Polygon transactions by the USDC.e contract will silently miss every post-migration transaction. Add the pUSD contract address as an alias.
- Annotate the snapshot conversion. Even though it is non-taxable in most regimes, log the conversion explicitly in your records: amount, block, timestamp, and a note that it is a 1:1 stablecoin migration. If your jurisdiction queries it later, you want a clean audit trail.
Israeli traders should consult Tax Guide for ITA-specific reporting; the migration itself does not change the standard treatment but the contract-address change matters for automated reporting tools.
Part 9: Pro Tips From Operators Who Lived the Switch
- Pin py-clob-client to
>=0.40,<0.50in requirements.txt. The 0.40 line is the minimum that signs pUSD orders correctly; pinning an upper bound protects against a future breaking change. - Re-approve allowances during a low-volume window. The
update_balance_allowancecall is one Polygon transaction; doing it during a fast market move is asking for the gas spike. - Snapshot your USDC.e balance before April 28. Even though conversion is automatic, a verifiable pre-snapshot balance is the cleanest way to dispute any reconciliation issue.
- Cancel resting orders manually before the snapshot. They were canceled by the venue anyway; doing it yourself gives you a clean ledger entry instead of a "system cancel" line.
- Watch for stale dashboards. Third-party Polymarket dashboards (PolymarketAnalytics, Polynance, etc.) took two-to-three days to re-parse pUSD events. Your bot's local DB may be ahead of public dashboards for a few days.
- Bridge USDC.e dust on your own schedule. Most accounts have a few cents of leftover USDC.e from old fee rebates or peer transfers. Use Circle's CCTP or the standard Polygon Portal bridge - no rush.
- Keep the old USDC.e address in your block-explorer alerts. If anything ever sweeps from your proxy in USDC.e post-migration, that's a red flag worth investigating immediately.
Wie geht es weiter?
- Polymarket API Guide - the full API guide, updated for pUSD
- Deposit Guide - depositing USDC and receiving pUSD inside the app
- Withdraw Guide - withdrawing pUSD as native USDC to an external wallet
- Tools & Resources - third-party dashboards now updated for pUSD
- Glossary - plain-English definitions for every term used here
Kernaussage
The Polymarket pUSD migration is a low-risk one-time refactor for any operator who already runs a Polymarket bot. Bump py-clob-client to 0.40+, re-approve pUSD allowances, run a $1 smoke test, and resume. The infrastructure underneath (CTF, condition IDs, token IDs, API keys) did not change, so the surface area is small and the rollback story is clean.











