Skip to main content
PolyUSD (pUSD) is the collateral token for Polymarket’s V2 exchange system. It is backed 1:1 by USDC and replaces USDC.e as the exchange collateral. To trade on V2, you need PolyUSD. Token info: Name: Polymarket USD | Symbol: pUSD | Decimals: 6 | View on Polygonscan

How PolyUSD Works

According to Polymarket’s announcement, PolyUSD is backed 1:1 by USDC. Power users and API traders can wrap either USDC or USDC.e into PolyUSD. For most frontend users, the transition is seamless — the Polymarket UI handles wrapping automatically with a one-time approval. There are two wrapping paths:
PathContractInput TokenStatus
Collateral Onramp0x93070a847efef7f70739046a929d47a521f5b8eeUSDC.e (bridged)Active — working today
PermissionedRamp0xebc2459ec962869ca4c0bd1e06368272732bcb08Native USDC (Circle)Not active yet — deployed but zero transactions
Both paths produce the same PolyUSD token. The V2 exchange doesn’t care how you obtained your PolyUSD.
The USDC.e → Onramp path is what’s working right now. We’ve tested it on mainnet and verified the full flow. The native USDC path via the PermissionedRamp exists on-chain but has not processed any transactions yet. When Polymarket activates it, wrapping native USDC will also be supported.

Quick Reference

Address
PolyUSD Token0xc011a7e12a19f7b1f670d46f03b03f3342e82dfb
Collateral Onramp (USDC.e → PolyUSD)0x93070a847efef7f70739046a929d47a521f5b8ee
Collateral Offramp (PolyUSD → USDC.e)0x2957922eb93258b93368531d39facca3b4dc5854
PermissionedRamp (native USDC, not yet active)0xebc2459ec962869ca4c0bd1e06368272732bcb08
USDC.e (bridged USDC)0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
Backing Vault0xC417fD8E9661c0d2120B64a04Bb3278C17E99DB1

Wrapping: USDC.e → PolyUSD (Active Path)

To get PolyUSD today, wrap your USDC.e through the Collateral Onramp contract.

Steps

  1. Approve the Onramp to spend your USDC.e
  2. Call wrap(underlyingToken, recipient, amount) on the Onramp
import { ethers } from "ethers";

const provider = new ethers.JsonRpcProvider("YOUR_RPC_URL");
const wallet = new ethers.Wallet("YOUR_PRIVATE_KEY", provider);

const USDC_E = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
const ONRAMP = "0x93070a847efef7f70739046a929d47a521f5b8ee";

// 1. Approve Onramp for USDC.e
const usdc = new ethers.Contract(USDC_E, [
  "function approve(address,uint256) returns (bool)",
  "function balanceOf(address) view returns (uint256)"
], wallet);

await (await usdc.approve(ONRAMP, ethers.MaxUint256)).wait();

// 2. Wrap USDC.e → PolyUSD
const amount = await usdc.balanceOf(wallet.address);
const wrapData = new ethers.Interface(["function wrap(address,address,uint256)"])
  .encodeFunctionData("wrap", [USDC_E, wallet.address, amount]);

const tx = await wallet.sendTransaction({ to: ONRAMP, data: wrapData, gasLimit: 300000 });
await tx.wait();

console.log("Wrapped", (Number(amount) / 1e6).toFixed(2), "USDC.e → PolyUSD");

Using the polynode SDK

The SDK handles wrapping automatically:
// Wrap 1 USDC.e → PolyUSD
let tx_hash = trader.wrap_to_polyusd(1_000_000).await?;

// Check balance
let balance = trader.get_polyusd_balance().await?;

Wrap Function Signature

function wrap(address underlyingToken, address recipient, uint256 amount)
  • underlyingToken — the USDC.e contract address (0x2791Bca1...)
  • recipient — who receives the PolyUSD (usually yourself)
  • amount — raw amount in 6-decimal units (1 USDC = 1,000,000)

Unwrapping: PolyUSD → USDC.e

To withdraw from V2, unwrap your PolyUSD back to USDC.e through the Collateral Offramp.

Steps

  1. Approve the Offramp to spend your PolyUSD
  2. Call unwrap(underlyingToken, recipient, amount) on the Offramp
The function signature is identical to wrapping:
function unwrap(address underlyingToken, address recipient, uint256 amount)

How It Works Under the Hood

PolyUSD is backed 1:1 by collateral held in a vault contract (0xC417fD8E...). When you wrap:
  1. Your USDC.e transfers to the vault
  2. PolyUSD is minted to your wallet
When you unwrap:
  1. Your PolyUSD is burned
  2. USDC.e is released from the vault to your wallet
During V2 trade settlements, the exchange automatically handles PolyUSD ↔ USDC.e conversion through the CTFCollateralAdapter. The ConditionalTokens contract underneath still uses USDC.e for position splitting — PolyUSD is the user-facing layer that sits on top.
The vault currently holds USDC.e as the backing collateral. Polymarket has stated that PolyUSD is backed 1:1 by USDC. A PermissionedRamp contract exists for native USDC wrapping but is not yet active. When it activates, the vault may hold a mix of USDC.e and native USDC, but PolyUSD remains 1:1 redeemable regardless of the backing composition.

Tracking PolyUSD Events

polynode detects PolyUSD wrapping and unwrapping through the settlement stream. These appear as deposit events:
  • Wrap (deposit): direction: "deposit", from is the Onramp contract
  • Unwrap (withdrawal): direction: "withdrawal", to is the user wallet
Subscribe to deposits on the WebSocket to receive these events. Internal settlement wraps/unwraps (between exchange and adapter contracts) are filtered out automatically.

Key Facts

  • Decimals: 6 (same as USDC)
  • Backing: 1:1 by USDC (currently held as USDC.e in the vault)
  • Wrapping: USDC.e via Onramp (active) or native USDC via PermissionedRamp (not yet active)
  • Proxy: ERC-1967 upgradeable proxy
  • Chain: Polygon mainnet (chain ID 137)
  • Minimum wrap: No minimum (tested with amounts as low as $0.007)