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 supports both Ethers v5 and Viem wallets:
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();
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
Support
If you encounter issues or have questions about using the relayer client, please contact support@polymarket.com.