# Polymarket Plugin

The Polymarket plugin targets Polymarket V2 on Polygon production and Polygon Amoy testnet. It exposes read-only Fox tools plus stateless primitives that higher layers can compose into `setup`, `deposit`, `place`, and `cancel` flows.

## Wallet Integration

The plugin expects an `EVMWalletClient` from Fox. For V2 write flows, the owner EOA signs CLOB auth and deposit-wallet batch typed data, while the order maker/funder is the deterministic deposit wallet. Orders must use `signatureType=3` (`POLY_1271`).

```ts
import { getTools } from "@metamask/fox-sdk";
import { polymarket } from "@metamask/fox-sdk/plugins/polymarket";

const tools = await getTools({
  wallet,
  plugins: [polymarket()],
});
```

## Deposit Wallet Flow

External orchestrators can use `createPolymarketToolkit(...)` to get the Polymarket primitives grouped under one stateless facade:

```ts
import { createPolymarketToolkit, OrderType, POLYMARKET_ASSET_TYPES } from "@metamask/fox-sdk/plugins/polymarket";

const polymarket = createPolymarketToolkit({
  chainId: 137,
  relayerUrl,
});

const depositWalletAddress = await polymarket.depositWallet.deriveAddressForWallet({
  walletClient,
});
const book = await polymarket.clob.getOrderBook(tokenId);
```

### Relayer URL contract

> **`relayerUrl` is the MetaMask Predict relayer proxy URL — not Polymarket's public relayer (`relayer.polymarket.com`).**

The proxy accepts a single `POST /transaction` envelope of the shape `{ path, method, body | query }` and forwards to the underlying `@polymarket/builder-relayer-client` routes (`/submit`, `/nonce`, `/transaction`, `/deployed`). Pointing this at Polymarket's public relayer will produce 404s. The plugin reuses Polymarket's request *builders* (`buildDepositWalletCreateRequest`, `buildDepositWalletBatchRequest`) but owns the transport so the same code path works with either MetaMask's proxy or a test fixture.

Transient relayer 5xx responses are retried up to `maxAttempts` (default 3) with exponential backoff (`backoffMs * 2^N`, default base 250ms). 4xx responses are not retried.

The toolkit does not retain wallets, credentials, or relayer secrets. Pass them into the specific call that needs them so application layers can own secret lifetime, confirmations, retries, and persistence.

## Prediction Market Flows

### Discover markets

Use the read-only tools for agent-facing market discovery, or call the Gamma/CLOB primitives directly from a consumer:

```ts
const markets = await polymarket.gamma.getMarkets({
  active: true,
  closed: false,
  acceptingOrders: true,
  limit: 20,
});

const market = await polymarket.gamma.getMarket("example-market-slug");
const book = await polymarket.clob.getOrderBook(tokenId);
const tickSize = await polymarket.clob.getTickSize(tokenId);
const quote = polymarket.preflight.buildQuoteFromOrderBook({
  book,
  side: "BUY",
  size: 10,
  tickSize,
});
```

### Set up a wallet

Before placing orders, the owner EOA needs CLOB API credentials and a deterministic deposit wallet:

```ts
const credentials = await polymarket.auth.createOrDeriveApiKey({ walletClient });
const depositWalletAddress = await polymarket.depositWallet.deriveAddressForWallet({
  walletClient,
});

const deployed = await polymarket.depositWallet.isDeployed({
  ...relayer,
  walletClient,
  address: depositWalletAddress,
});

if (!deployed) {
  const deployment = await polymarket.depositWallet.deploy({
    ...relayer,
    walletClient,
  });
  // Persist deployment.transactionId in the consumer layer if not waiting.
}
```

### Fund and approve the deposit wallet

On Polygon production, Fox can build the USDC.e -> pUSD funding transaction plan. On Amoy, fund the deposit wallet manually with test pUSD before continuing.

```ts
const fundingPlan = polymarket.funding.buildPusdWrapTransactions({
  amount: 1_000_000n,
  recipient: depositWalletAddress,
});

for (const tx of fundingPlan.transactions) {
  await walletClient.sendTransaction(tx);
}

const gaps = await polymarket.preflight.checkDepositWalletAllowanceGaps({
  walletClient,
  depositWalletAddress,
});

if (gaps.length > 0) {
  const approval = await polymarket.depositWallet.executeBatch({
    ...relayer,
    walletClient,
    depositWalletAddress,
    calls: polymarket.preflight.buildDepositWalletPreflightCalls(gaps),
  });
  // Persist approval.transactionId in the consumer layer if not waiting.
}
```

### Place and cancel orders

Orders are signed by the owner EOA while the deterministic deposit wallet is passed as the CLOB funder. Higher layers should resolve user intent, validate balances, ask for confirmation, and persist order/job state.

```ts
const client = polymarket.clob.createClient({
  walletClient,
  credentials,
  funderAddress: depositWalletAddress,
});

await polymarket.balanceAllowance.update({
  walletClient,
  credentials,
  params: { assetType: POLYMARKET_ASSET_TYPES.COLLATERAL },
});

const tickSize = await polymarket.clob.getTickSize(tokenId, client);
const negRisk = await polymarket.clob.getNegRisk(tokenId, client);

await polymarket.clob.postOrder(
  client,
  {
    tokenId,
    side: "BUY",
    price: 0.52,
    size: 10,
    tickSize,
    negRisk,
  },
  { orderType: OrderType.GTC }
);

await polymarket.clob.cancelOrders(client, { orderId: "0x..." });
```

### Read positions and orders

Use the data and CLOB read helpers for portfolio views or watch flows:

```ts
const positions = await polymarket.data.getPositions({
  user: depositWalletAddress,
});

const redeemed = await polymarket.data.getActivity({
  user: depositWalletAddress,
  type: "REDEEM",
});

const orders = await polymarket.clob.getOpenOrders(client, {
  market: conditionId,
});
```

The recommended setup order is:

1. `createOrDeriveApiKey({ walletClient })` for CLOB L1/L2 credentials.
2. `deriveAddressForWallet(...)` to compute the deposit wallet.
3. `isDeployed(...)` and `deploy(...)` for first-time setup.
4. `checkDepositWalletAllowanceGaps(...)` plus `executeBatch(...)` for pUSD/CTF approvals.
5. `updateBalanceAllowance(...)` after funding or allowance changes so CLOB sees the latest deposit-wallet balance.

`deploy(...)` and `executeBatch(...)` return immediately after relayer submission so orchestrators can persist and resume jobs. Direct callers that want the Polymarket docs' blocking flow can use `deployAndWait(...)` or `executeBatchAndWait(...)`, which wait for `STATE_CONFIRMED` before returning `confirmed`.

The MetaMask Predict relayer URL is supplied by the caller or toolkit configuration through `PolymarketRelayerConfig`. Fox never stores relayer jobs or runtime state.

## Networks

- Polygon `137` uses `https://clob.polymarket.com` by default.
- Polygon Amoy `80002` uses `https://clob-staging.polymarket.com` by default.

The USDC.e -> pUSD funding helpers are configured only for Polygon production. On Amoy, fund the deterministic deposit wallet manually with test pUSD, then run allowance preflight and balance-allowance sync before placing orders.

## Layering

Fox does not store API keys, relayer jobs, confirmations, or CLI session state. Those belong in `agentic-sdk` or another application layer.
