Chapter 36 of 36

The Short Version

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 the archived py-clob-client 0.34.x must be swapped for py-clob-client-v2. This guide walks through the exact code, contract, and approval changes needed to keep a bot running through and after the cutover.

What you'll learn: why Polymarket moved away from USDC.e, what changed at the contract level, the exact py-clob-client upgrade path, how to re-approve allowances for the new collateral, how to verify your balance after the swap, and how to handle the legacy USDC.e dust most accounts now hold.
Prerequisites: you should already have a working Polymarket account, basic familiarity with Polygon contracts, and an existing bot or manual API workflow that pre-dates April 28, 2026. If you're starting fresh today, just install the latest SDK and skip to Chapter Four - you'll never need to touch USDC.e.
01
Chapter One

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.

TokenIssuerContract on PolygonReserve type
USDC.ePolygon PoS bridge0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174Bridged from Ethereum mainnet
USDC (native)Circle0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359Native, issued directly on Polygon
pUSDPolymarket collateral contractSee docs.polymarket.com/concepts/pusd1:1 backed by USDC, enforced on-chain, redeemable anytime

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.

02
Chapter Two

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 minted only when USDC is wrapped through Polymarket's collateral contract, and is redeemable 1:1 for native USDC at any time, with no fee on the conversion (network gas still applies). The backing is enforced on-chain: the wrapper contract holds the underlying USDC and is itself the redemption mechanism. There is no off-chain custodian, no algorithmic peg, and no fractional reserve.

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.

Backing and redemption: pUSD's backing is enforced by its smart contract on Polygon - the contract holds the underlying USDC and lets you unwrap back to native USDC 1:1 at any time. There is no algorithmic peg and no fractional reserve, so the reserve is verifiable directly on-chain rather than through an off-chain attestation. Read the mechanics at docs.polymarket.com/concepts/pusd.
03
Chapter Three

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.

04
Chapter Four

Part 4: API and Bot Operators - Critical Changes

This is the part that will break a bot if you don't act.

What changed in the order signature: CLOB orders are signed via EIP-712 and reference the collateral asset address as part of the typed data. Pre-migration, that address was USDC.e (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's py-clob-client-v2 has full pUSD / V2 support. The old 0.34.x line is archived V1 and signs the wrong (USDC.e) domain - do not use it. (There is no "py-clob-client 0.40"; if a guide says that, it is wrong.)

# Bump to a pUSD-aware release
pip install py-clob-client-v2          # the V2 client; the old 0.34.x line is archived V1
# pUSD collateral is 0xC011a7E12a19f7B1f670d46F03B03f3342E82DFB on Polygon

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_v2 import ClobClient

creds = ClobClient(host="https://clob.polymarket.com", chain_id=137,
                   key=os.environ["POLY_PRIVATE_KEY"]).create_or_derive_api_key()
client = ClobClient(
    host="https://clob.polymarket.com",
    chain_id=137,
    key=os.environ["POLY_PRIVATE_KEY"],
    creds=creds,                       # V2: creds in the constructor (no set_api_creds)
    funder=os.environ["POLY_FUNDER"],
    signature_type=1,  # POLY_PROXY for Magic-link accounts
)

# One-time: approve pUSD for the V2 exchange contracts before trading
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_key()    # V2 method; idempotent re-derive
# In V2 you pass creds= into the ClobClient constructor (there is no set_api_creds)

# Persist to your .env
print(creds.key, creds.secret, creds.passphrase)
05
Chapter Five

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_v2 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_v2 import OrderArgs, Side, OrderType, PartialCreateOrderOptions
resp = client.create_and_post_order(           # V2: build + sign + post in one call
    order_args=OrderArgs(token_id=test_token_id, price=0.05, side=Side.BUY, size=20),
    options=PartialCreateOrderOptions(tick_size="0.01"),
    order_type=OrderType.GTC,                  # $1 notional at $0.05, nowhere near the touch
)
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.

Time the upgrade carefully: if you ran the bot continuously through the snapshot block, your local order book state probably diverged. Always reconcile against REST snapshots after a major venue change before quoting size.
06
Chapter Six

Part 6: Common Errors and Fixes

Error or symptomCauseFix
signature verification failedOrder signed against USDC.e EIP-712 domainSwitch to py-clob-client-v2 (the archived 0.34.x signs the old USDC.e domain)
INSUFFICIENT_ALLOWANCE on every orderNo pUSD allowance from your proxy to CTF ExchangeRun update_balance_allowance(asset_type="COLLATERAL") once
invalid maker assetHard-coded USDC.e address still in your configReplace any hard-coded collateral address with SDK constant
Wallet shows USDC.e balance > 0 after migration"Dust" tokens left over from a third-party transferBridge USDC.e back to native USDC on Circle's CCTP, or leave it
WebSocket reconnect produces empty bookOld subscription used a stale market state from before snapshotDrop local cache, re-fetch REST book, then resubscribe
Withdraw to external wallet shows pUSD instead of USDCYou selected "pUSD" instead of "USDC" in the withdraw modalPick "USDC" - the bridge converts pUSD → native USDC at 1:1
07
Chapter Seven

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 asset field reads "pUSD" instead of "USDC.e" in fill events.
  • Gamma and Data APIs: unauthenticated, unchanged. They never referenced the collateral token directly.
One small UI change: the Polymarket proxy wallet view now shows balances in pUSD, with a 1:1 USD label. Block explorers (PolygonScan, Polygonscan API) show pUSD ERC-20 transfers in the proxy wallet's transaction history. Old USDC.e transfers remain visible in history; your address will simply have two ERC-20 token rows for a while.
08
Chapter Eight

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:

  1. 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.
  2. 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.

09
Chapter Nine

Part 9: Pro Tips From Operators Who Lived the Switch

  1. Pin py-clob-client-v2 (>=1.0) in requirements.txt. It signs pUSD / V2 orders correctly; the archived 0.34.x line does not.
  2. Re-approve allowances during a low-volume window. The update_balance_allowance call is one Polygon transaction; doing it during a fast market move is asking for the gas spike.
  3. 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.
  4. 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.
  5. 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.
  6. 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.
  7. 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.

What's Next?

Key takeaway

The Polymarket pUSD migration is a low-risk one-time refactor for any operator who already runs a Polymarket bot. Switch to py-clob-client-v2, 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.