✗ BEFORE — V1 (broken on mainnet)
EOA is the maker · CLOB rejects it
Privy EOA wallet
holds pUSD collateral · USDC.e · CTF outcome positions
maker = EOA
funder = EOA
│ ClobClient({ signatureType: EOA(0) })
buy / sell · approvals · wrap · split / merge / redeem / withdraw
▼
All flows originate from the EOA
• createAndPostMarketOrder → maker = EOA
• approveAllWithViemAccount → EOA approves CTF/NegRisk
• CollateralOnramp.wrap(USDC.e, EOA, amt) → pUSD to EOA
• split / merge / redeem / withdraw → EOA sendFn → adapters
▼ POST /order
Polymarket CLOB API
reads buying power from the deposit wallet, not the EOA
✗ HTTP 400 — order rejected
"maker address not allowed, please use the deposit wallet flow"
Live symptom: agent shows Polygon pUSD: $2.00
but Polymarket CLOB: $0.00 (not initialized) —
the pUSD sits on the EOA, which the CLOB never reads.
✓ AFTER — V2 (deposit-wallet model)
deposit wallet is the maker/funder · EOA only signs
Privy EOA wallet — OWNER / SIGNER
signs orders & owns the deposit wallet · holds USDC.e for funding
signer
pays USDC.e on wrap
│ owns & operates (via relayer)
▼
@polymarket/relayer-client
deriveDepositWalletAddress · deployDepositWallet
executeDepositWalletBatch(calls[]) · pollUntilState(STATE_CONFIRMED)
│ WALLET-CREATE → STATE_CONFIRMED · batched calls
▼
Deposit Wallet — ERC-1967 proxy
CREATE2 via factory 0x0000…Cc07, deployed by relayer
holds pUSD collateral + CTF positions · IS the CLOB maker/funder
maker = signer = deposit wallet
│ ClobClient({ signatureType: POLY_1271(3), funderAddress: depositWallet })
wrap _to = deposit wallet · approvals/split/merge/redeem/withdraw via relayer batch
▼ POST /order
Polymarket CLOB API
EIP-1271 sig verified against the deployed proxy
✓ order matched
pUSD lives in the deposit wallet — exactly where the CLOB reads buying
power. Deploying the proxy on-chain is what fixes the
#64 "signer address has to be the address of the API KEY"
caveat (POLY_1271 needs deployed bytecode to verify against).