Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.polymarket.com/llms.txt

Use this file to discover all available pages before exploring further.

Deposit wallets are the new wallet path for new API users. They replace the current proxy/Safe onboarding path for those new API users only. Existing users are unaffected in this phase and should continue using their current proxy or Safe setup. This rollout addresses the sustained rise in ghost fills that has caused instability for liquidity providers. The new flow makes the user’s trading wallet a deterministic smart account whose signatures are validated by the CLOB through ERC-1271.
This guide is for developers integrating directly with the APIs or SDKs. It does not change existing user balances, existing proxy wallets, or existing Safes.
Until the production rollout, test against the preprod API URLs. On Monday, when deposit wallets are released in production, the integration code stays the same: replace the preprod relayer and CLOB URLs with the production URLs in your SDK or API configuration.Relayer preprod URL: https://relayer-v2-preprod-int.polymarket.com/

What Changes

AreaBeforeNew API user deposit wallet flow
Wallet created for new API usersProxy wallet or SafeDeposit wallet
Wallet deploymentExisting relayer Safe/proxy flowRelayer WALLET-CREATE
Deployment signatureSafe deployment flow includes user signingNo user signature in the WALLET-CREATE payload
Wallet callsSafe/proxy relayer transactionsRelayer WALLET batches
Order signature type0, 1, or 23, also called POLY_1271
Order makerEOA, proxy, or SafeDeposit wallet address
Order signer fieldEOA for existing typesDeposit wallet address
Signing keyUser EOA or session signerDeposit wallet owner or approved session signer

Mental Model

A deposit wallet is a per-user ERC-1967 proxy deployed by a deposit wallet factory. The wallet holds pUSD and conditional tokens on-chain. The owner or session signer signs two different kinds of payloads:
  1. A deposit wallet Batch for on-chain wallet calls. This is submitted to the relayer as a WALLET transaction.
  2. A CLOB order with signatureType = 3. The CLOB validates this through ERC-1271 on the deposit wallet.
These signatures are not interchangeable. A WALLET batch uses a normal 65-byte EIP-712 signature over the DepositWallet Batch type. A CLOB order uses an ERC-7739-wrapped POLY_1271 signature and is longer than a normal ECDSA signature.

New API User Flow

1

Create or identify the owner signer

Use the EOA or session signer that will own the deposit wallet. This signer is also the key that signs deposit wallet batches and CLOB order payloads unless your session signer flow delegates signing elsewhere.
2

Deploy the deposit wallet

Submit a relayer WALLET-CREATE request. The body only needs the transaction type, owner address, and deposit wallet factory address.The deposit wallet address is deterministic. TypeScript relayer users can call deriveDepositWalletAddress(), and Python relayer users can call get_expected_deposit_wallet(). Other integrations should store the address returned by onboarding or derive it with the deterministic formula below.
3

Fund the deposit wallet

Transfer pUSD to the deposit wallet address. pUSD held by the EOA does not count as CLOB buying power for deposit wallet orders.
4

Approve trading contracts from the wallet

Approvals must be made from the deposit wallet, not from the owner EOA. Build ERC-20 or ERC-1155 approval calldata and submit it through a relayer WALLET batch.
5

Sync CLOB balances

After funding or changing allowances, call the CLOB balance allowance update endpoint through the SDK or API. The request must use signature_type = 3.
6

Place orders with POLY_1271

Initialize the CLOB client with the deposit wallet as the funder and POLY_1271 as the signature type. Orders must have both maker and signer set to the deposit wallet address.

SDK Users

Use a relayer client or the raw relayer API for wallet deployment and wallet batches. Use the CLOB client for order signing, posting, cancelling, balances, and account data.
Use the TypeScript clients with deposit wallet support: @polymarket/builder-relayer-client 0.0.9 and @polymarket/clob-client-v2 1.0.3-canary.0.
npm install @polymarket/builder-relayer-client@0.0.9 @polymarket/clob-client-v2@1.0.3-canary.0 @polymarket/builder-signing-sdk viem

Deploy the Wallet

import {
  BuilderApiKeyCreds,
  BuilderConfig,
} from "@polymarket/builder-signing-sdk";
import { RelayClient } from "@polymarket/builder-relayer-client";
import { createWalletClient, Hex, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { polygon } from "viem/chains";

const relayerUrl = process.env.RELAYER_URL!;
const chainId = Number(process.env.CHAIN_ID ?? 137);
const account = privateKeyToAccount(process.env.PRIVATE_KEY as Hex);
const walletClient = createWalletClient({
  account,
  chain: polygon,
  transport: http(process.env.RPC_URL),
});

const builderCreds: BuilderApiKeyCreds = {
  key: process.env.BUILDER_API_KEY!,
  secret: process.env.BUILDER_SECRET!,
  passphrase: process.env.BUILDER_PASS_PHRASE!,
};

const builderConfig = new BuilderConfig({
  localBuilderCreds: builderCreds,
});

const relayer = new RelayClient(
  relayerUrl,
  chainId,
  walletClient,
  builderConfig,
);

const depositWalletAddress = await relayer.deriveDepositWalletAddress();
const response = await relayer.deployDepositWallet();
const confirmed = await response.wait();
deployDepositWallet() submits a WALLET-CREATE transaction. It does not add a user signature to the deployment body.

Execute a Wallet Batch

import type { DepositWalletCall } from "@polymarket/builder-relayer-client";

const calls: DepositWalletCall[] = [
  {
    target: process.env.PUSD_ADDRESS!,
    value: "0",
    data: approveCalldata,
  },
];

const deadline = Math.floor(Date.now() / 1000 + 240).toString();
const response = await relayer.executeDepositWalletBatch(
  calls,
  depositWalletAddress,
  deadline,
);
const confirmed = await response.wait();
The TypeScript relayer client fetches the current WALLET nonce before signing and submitting the batch. The SDK signs the batch with this EIP-712 domain before submitting it to the relayer:
{
  name: "DepositWallet",
  version: "1",
  chainId,
  verifyingContract: depositWalletAddress,
}

Trade From the Deposit Wallet

import {
  AssetType,
  ClobClient,
  OrderType,
  Side,
  SignatureTypeV2,
} from "@polymarket/clob-client-v2";

const creds = {
  key: process.env.CLOB_API_KEY!,
  secret: process.env.CLOB_SECRET!,
  passphrase: process.env.CLOB_PASS_PHRASE!,
};

const clob = new ClobClient({
  host: process.env.CLOB_API_URL!,
  chain: chainId,
  signer: walletClient,
  creds,
  signatureType: SignatureTypeV2.POLY_1271,
  funderAddress: depositWalletAddress,
});

await clob.updateBalanceAllowance({ asset_type: AssetType.COLLATERAL });

const order = await clob.createAndPostOrder(
  {
    tokenID: process.env.TOKEN_ID!,
    price: 0.5,
    size: 10,
    side: Side.BUY,
  },
  { tickSize: "0.01", negRisk: false },
  OrderType.GTC,
);

API Users

Direct API integrations need to implement the same two relayer operations and the same CLOB order signature shape used by the SDKs.

Deploy a Deposit Wallet

Submit this body to the relayer /submit endpoint:
{
  "type": "WALLET-CREATE",
  "from": "0xOwnerAddress",
  "to": "0x00000000000Fb5C9ADea0298D729A0CB3823Cc07"
}
Field meanings:
FieldDescription
typeMust be WALLET-CREATE
fromOwner address for the deposit wallet
toDeposit wallet factory address for the active chain and environment
Current factory addresses:
ChainDeposit wallet factory
Polygon mainnet 1370x00000000000Fb5C9ADea0298D729A0CB3823Cc07
There is no user signature field in this payload. After submission, poll the relayer transaction until it reaches STATE_MINED or STATE_CONFIRMED. Store the deployed wallet address from the WalletDeployed event, from your onboarding flow, or derive it deterministically using the SDK’s chain config. Deterministic address derivation follows the relayer clients:
walletId = bytes32(owner) // owner address left-padded to 32 bytes
args = abi.encode(factory, walletId)
salt = keccak256(args)
bytecodeHash = SoladyLibClone.initCodeHashERC1967(implementation, args)
depositWallet = CREATE2(factory, salt, bytecodeHash)

Submit a Deposit Wallet Batch

For wallet actions such as token approvals, transfers, withdrawals, splits, or merges, fetch the current WALLET nonce for the owner address, then sign a Batch with the owner or session signer:
GET /nonce?address=0xOwnerAddress&type=WALLET
const types = {
  Call: [
    { name: "target", type: "address" },
    { name: "value", type: "uint256" },
    { name: "data", type: "bytes" },
  ],
  Batch: [
    { name: "wallet", type: "address" },
    { name: "nonce", type: "uint256" },
    { name: "deadline", type: "uint256" },
    { name: "calls", type: "Call[]" },
  ],
};

const domain = {
  name: "DepositWallet",
  version: "1",
  chainId,
  verifyingContract: depositWalletAddress,
};

const message = {
  wallet: depositWalletAddress,
  nonce,
  deadline,
  calls,
};
Submit the signed batch to the relayer:
{
  "type": "WALLET",
  "from": "0xOwnerAddress",
  "to": "0x00000000000Fb5C9ADea0298D729A0CB3823Cc07",
  "nonce": "0",
  "signature": "0x65ByteBatchSignature",
  "depositWalletParams": {
    "depositWallet": "0xDepositWallet",
    "deadline": "1760000000",
    "calls": [
      {
        "target": "0xTokenOrContract",
        "value": "0",
        "data": "0xCalldata"
      }
    ]
  }
}
The signature in a WALLET request is a normal 65-byte EIP-712 signature with a 0x prefix. This is different from the CLOB order signature described below.

Place CLOB Orders

For deposit wallet orders, the raw order inside the /order request must use signatureType = 3:
{
  "deferExec": false,
  "order": {
    "salt": 123456789,
    "maker": "0xDepositWallet",
    "signer": "0xDepositWallet",
    "tokenId": "TOKEN_ID",
    "makerAmount": "5000000",
    "takerAmount": "10000000",
    "side": "BUY",
    "expiration": "0",
    "signatureType": 3,
    "timestamp": "1760000000",
    "metadata": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "builder": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "signature": "0xWrapped1271Signature"
  },
  "owner": "CLOB_API_KEY",
  "orderType": "GTC"
}
The signature is not the raw order EIP-712 signature. It is an ERC-7739-wrapped signature that lets the deposit wallet validate the order through ERC-1271. The owner or session signer signs a nested TypedDataSign payload under the correct CTF Exchange V2 domain. The nested wallet fields are:
FieldValue
nameDepositWallet
version1
chainIdCurrent chain ID
verifyingContractDeposit wallet address
salt0x0000000000000000000000000000000000000000000000000000000000000000
The SDKs build this wrapper for you when you configure POLY_1271 and the deposit wallet funder address.
If you sign the CLOB order as a normal EOA order, or if maker and signer are not both the deposit wallet address, the order will fail ERC-1271 validation. POLY_1271 is supported on V2 orders only.

Sync Balance and Allowance

After funding the deposit wallet or approving contracts from it, update the CLOB balance cache using signature_type = 3.
GET /balance-allowance/update?asset_type=COLLATERAL&signature_type=3
For conditional tokens, include the token ID:
GET /balance-allowance/update?asset_type=CONDITIONAL&token_id=TOKEN_ID&signature_type=3
Use normal CLOB L2 authentication headers for these requests. Relayer auth and CLOB auth are separate systems.

Implementation Checklist

  • Use deposit wallets only for new API users in this phase.
  • Keep existing proxy and Safe users on their current signature type.
  • Deploy the deposit wallet with relayer WALLET-CREATE.
  • Store or derive the user’s deposit wallet address.
  • Transfer pUSD to the deposit wallet, not only to the owner EOA.
  • Approve pUSD and conditional token spenders through a WALLET batch.
  • Fetch the current WALLET nonce fresh before each direct API batch.
  • Use POLY_1271 for CLOB orders from the deposit wallet.
  • Set CLOB order maker and signer to the deposit wallet address.
  • Sync CLOB balances with signature_type = 3 after deposits and approvals.
  • Use the correct exchange or negative-risk exchange verifying contract for the market being traded.

Common Issues

Check all four signature inputs: signatureType must be 3, order maker must be the deposit wallet, order signer must be the deposit wallet, and the order signature must be the ERC-7739-wrapped POLY_1271 signature. Also confirm the order was signed against the correct CTF Exchange V2 verifying contract for the market.
Fetch the current WALLET nonce fresh from the relayer before signing the batch. Confirm the deadline is still in the future and within the relayer’s accepted range. The WALLET batch signature should be a normal 65-byte EIP-712 signature over DepositWallet Batch.
Confirm pUSD is held by the deposit wallet address. Then update the CLOB balance cache with signature_type = 3. pUSD sitting on the owner EOA does not fund deposit wallet orders.
Approvals must come from the deposit wallet. An EOA approve() transaction does not approve spending from the deposit wallet. Submit approval calldata through a relayer WALLET batch.
Relayer auth and CLOB auth are independent. Use the auth method required by your relayer environment for /submit. Use CLOB L1/L2 authentication for order and balance endpoints. Do not reuse relayer cookies or headers as CLOB auth.