Skip to main content

Overview

The Polymarket Relayer Client allows builders to route on-chain transactions through Polymarket’s Polygon relayer infrastructure. This provides several key benefits:
  • Gasless Transactions: Polymarket pays for all gas fees on your behalf
  • Safe Wallet Deployment: Deploy Safe Wallets for your users and customers
  • Token Approvals: Set allowances for trading tokens
  • CTF Operations: Execute Conditional Token Framework (CTF) operations including:
    • Splitting positions
    • Merging positions
    • Redeeming positions
    • Converting positions

Installation

npm install @polymarket/builder-relayer-client
# or
pnpm install @polymarket/builder-relayer-client

Quick Start

Relayer URL

The Polymarket relayer is publicly available at:
https://relayer-v2.polymarket.com/

Basic Setup

The relayer client is available for both TypeScript and Python:
import { ethers } from "ethers";
import { RelayClient } from "@polymarket/builder-relayer-client";
import { BuilderApiKeyCreds, BuilderConfig } from "@polymarket/builder-signing-sdk";

const relayerUrl = process.env.POLYMARKET_RELAYER_URL;
const chainId = 137; // Polygon mainnet

// Create wallet
const provider = new ethers.providers.JsonRpcProvider(process.env.RPC_URL);
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);

// Configure builder credentials
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
});

// Initialize client
const client = new RelayClient(relayerUrl, chainId, wallet, builderConfig);

Remote Signing

For enhanced security, you can use remote signing to keep your builder credentials on a secure server:
import { BuilderConfig } from "@polymarket/builder-signing-sdk";

const builderConfig = new BuilderConfig({
    remoteBuilderConfig: {url: "http://localhost:3000/sign"}
});

const client = new RelayClient(relayerUrl, chainId, wallet, builderConfig);

Core Features

Deploying Safe Wallets

Deploy a Safe wallet for your user with a single call. Polymarket pays the gas fees:
const response = await client.deploySafe();
const result = await response.wait();

if (result) {
    console.log("Safe deployed successfully!");
    console.log("Transaction Hash:", result.transactionHash);
    console.log("Safe Address:", result.proxyAddress);
} else {
    console.log("Safe deployment failed");
}

Setting Token Approvals

Set token allowances to enable trading. This example approves USDC spending for the Conditional Token Framework:
import { ethers } from "ethers";
import { Interface } from "ethers/lib/utils";
import { OperationType, SafeTransaction } from "@polymarket/builder-relayer-client";

// Define ERC20 approval interface
const erc20Interface = new Interface([{
    "constant": false,
    "inputs": [
        {"name": "_spender", "type": "address"},
        {"name": "_value", "type": "uint256"}
    ],
    "name": "approve",
    "outputs": [{"name": "", "type": "bool"}],
    "payable": false,
    "stateMutability": "nonpayable",
    "type": "function"
}]);

// Create approval transaction
function createApprovalTransaction(
    tokenAddress: string,
    spenderAddress: string
): SafeTransaction {
    return {
        to: tokenAddress,
        operation: OperationType.Call,
        data: erc20Interface.encodeFunctionData("approve", [
            spenderAddress,
            ethers.constants.MaxUint256
        ]),
        value: "0"
    };
}

// Execute the approval
const usdcAddress = "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174";
const ctfAddress = "0x4d97dcd97ec945f40cf65f87097ace5ea0476045";

const approvalTx = createApprovalTransaction(usdcAddress, ctfAddress);
const response = await client.executeSafeTransactions(
    [approvalTx],
    "Approve USDC for CTF"
);

const result = await response.wait();
console.log("Approval completed:", result?.transactionHash);

Monitoring Transaction Status

The relayer client provides built-in transaction monitoring:
// Automatic waiting (recommended)
const response = await client.executeSafeTransactions(transactions);
const result = await response.wait();

if (result) {
    console.log("Transaction confirmed:", result.transactionHash);
    console.log("Transaction state:", result.state);
} else {
    console.log("Transaction failed or timed out");
}

Transaction States

Transactions move through the following states:
  • STATE_NEW: Transaction received by relayer
  • STATE_EXECUTED: Transaction executed on-chain
  • STATE_MINED: Transaction included in a block
  • STATE_CONFIRMED: Transaction confirmed (final state)
  • STATE_FAILED: Transaction failed (terminal state)
  • STATE_INVALID: Transaction rejected as invalid (terminal state)

CTF Operations

The relayer client enables you to execute Conditional Token Framework operations for your users:

Split Positions

Split collateral tokens into conditional tokens representing different outcomes:
import { Interface } from "ethers/lib/utils";
import { OperationType, SafeTransaction } from "@polymarket/builder-relayer-client";

const ctfInterface = new Interface([
    "function splitPosition(address collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] partition, uint amount)"
]);

const splitTx: SafeTransaction = {
    to: ctfAddress,
    operation: OperationType.Call,
    data: ctfInterface.encodeFunctionData("splitPosition", [
        collateralToken,
        parentCollectionId,
        conditionId,
        partition,
        amount
    ]),
    value: "0"
};

const response = await client.executeSafeTransactions([splitTx], "Split position");
const result = await response.wait();

Merge Positions

Merge conditional tokens back into collateral:
const ctfInterface = new Interface([
    "function mergePositions(address collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] partition, uint amount)"
]);

const mergeTx: SafeTransaction = {
    to: ctfAddress,
    operation: OperationType.Call,
    data: ctfInterface.encodeFunctionData("mergePositions", [
        collateralToken,
        parentCollectionId,
        conditionId,
        partition,
        amount
    ]),
    value: "0"
};

const response = await client.executeSafeTransactions([mergeTx], "Merge position");
const result = await response.wait();

Redeem Positions

Redeem winning conditional tokens for collateral after market resolution:
const ctfInterface = new Interface([
    "function redeemPositions(address collateralToken, bytes32 parentCollectionId, bytes32 conditionId, uint[] indexSets)"
]);

const redeemTx: SafeTransaction = {
    to: ctfAddress,
    operation: OperationType.Call,
    data: ctfInterface.encodeFunctionData("redeemPositions", [
        collateralToken,
        parentCollectionId,
        conditionId,
        indexSets
    ]),
    value: "0"
};

const response = await client.executeSafeTransactions([redeemTx], "Redeem position");
const result = await response.wait();

Transaction Metadata

Use descriptive metadata to track transaction purposes:
Metadata is limited to 500 characters or less
await client.executeSafeTransactions(
    transactions,
    "User deposit: 100 USDC for market ABC123"
);

TypeScript Types

The relayer client is fully typed. Key types include:
interface SafeTransaction {
    to: string;
    operation: OperationType;
    data: string;
    value: string;
}

enum OperationType {
    Call = 0,
    DelegateCall = 1
}

enum RelayerTransactionState {
    STATE_NEW = "STATE_NEW",
    STATE_EXECUTED = "STATE_EXECUTED",
    STATE_MINED = "STATE_MINED",
    STATE_CONFIRMED = "STATE_CONFIRMED",
    STATE_FAILED = "STATE_FAILED",
    STATE_INVALID = "STATE_INVALID"
}

interface RelayerTransaction {
    transactionID: string;
    transactionHash: string;
    from: string;
    to: string;
    proxyAddress: string;
    data: string;
    state: string;
    type: string;
    metadata: string;
    createdAt: Date;
    updatedAt: Date;
}

Contract Addresses

Polygon Mainnet

  • USDC: 0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
  • CTF (Conditional Token Framework): 0x4d97dcd97ec945f40cf65f87097ace5ea0476045
  • CTF Exchange: 0x4bFb41d5B3570DeFd03C39a9A4D8dE6Bd8B8982E
  • Neg Risk CTF Exchange: 0xC5d563A36AE78145C45a50134d48A1215220f80a
These addresses are commonly used for token approvals and CTF operations.

Resources

TypeScript

Python

Additional Resources

Support

If you encounter issues or have questions about using the relayer client, please contact support@polymarket.com.