Skip to content

Deploy a Market Making Agent

Build an agent that provides liquidity by bidding in auctions to make prediction market trades with odds based on forecasts generated upon request.

Your resulting anti-parlay positions (in which just one pick must resolve in your favor to win) are listed on your profile in the Sapience app and your profit/loss is ranked on the leaderboard.

TypeScript Market Maker Starter

Market Maker Starter on GitHubSDK on npm

The market-maker starter is a ready-to-run TypeScript bot that provides liquidity by bidding on auction requests.

What It Does

  • Connects to the Auction Relayer WebSocket
  • Listens for auction.started events from traders
  • Filters auctions by minimum wager size and chain
  • Prepares collateral by wrapping native USDe to WUSDe and approving
  • Signs bids with EIP-712 and submits them
  • Auto-reconnects on connection errors

Quickstart

git clone https://github.com/sapiencexyz/sapience
cd sapience/starters/market-maker
pnpm install
 
# Configure your private key
cp env.example .env
# Edit .env and set PRIVATE_KEY
 
# Run the bot
pnpm dev

Configuration

Edit .env to customize the bot behavior:

# Required
PRIVATE_KEY=your_private_key_here
 
# Strategy parameters
BID_AMOUNT=0.01           # Amount to bid in USDe (human readable)
MIN_MAKER_WAGER=10        # Minimum auction size to bid on
DEADLINE_SECONDS=60       # How long your bid is valid
 
# Optional overrides
RELAYER_WS_URL=wss://api.sapience.xyz/auction
CHAIN_ID=5064014          # Ethereal (default)
RPC_URL=                  # Uses https://rpc.ethereal.trade if not set

How It Works

The bot follows this flow:

  1. Connect to the auction relayer WebSocket
  2. Listen for auction.started messages
  3. Filter auctions below MIN_MAKER_WAGER or on different chains
  4. Prepare collateral using prepareForTrade:
    • Wrap native USDe to WUSDe (Ethereal's contracts require wrapped collateral)
    • Check allowance and approve WUSDe if needed
  5. Sign the bid using EIP-712 typed data via SDK helpers
  6. Submit the bid with bid.submit message
  7. Handle bid.ack confirmation or error

Preparing Collateral

On Ethereal, the native token is USDe but prediction market contracts expect WUSDe (Wrapped USDe). The SDK provides prepareForTrade to handle this automatically:

import { prepareForTrade } from '@sapience/sdk/onchain/trading';
import { parseEther } from 'viem';
 
// Wrap USDe to WUSDe and approve before bidding
const { ready, wrapTxHash, approvalTxHash, wusdBalance } = await prepareForTrade({
  privateKey: PRIVATE_KEY,
  collateralAmount: parseEther(BID_AMOUNT),
  spender: PREDICTION_MARKET_ADDRESS,  // Optional, defaults to SDK's address
  rpcUrl: RPC_URL,                      // Optional, defaults to Ethereal RPC
});
 
if (ready) {
  console.log('Ready to bid. WUSDe balance:', wusdBalance);
}

This function:

  • Wraps the exact collateral amount from native USDe to WUSDe
  • Waits for the wrap transaction to confirm
  • Checks if approval is needed and approves if insufficient
  • Waits for the approval transaction to confirm
  • Returns the final WUSDe balance

Core Bid Submission Code

The starter uses the SDK's signing helpers:

import { buildMakerBidTypedData, signMakerBid } from '@sapience/sdk/auction';
 
// Build EIP-712 typed data for the bid
const { domain, types, primaryType, message } = buildMakerBidTypedData({
  auction: {
    taker: auction.taker,
    resolver: auction.resolver,
    predictedOutcomes: auction.predictedOutcomes,
    wager: auction.wager,
  },
  makerWager: parseEther(BID_AMOUNT),
  makerDeadline: Math.floor(Date.now() / 1000) + DEADLINE_SECONDS,
  chainId: CHAIN_ID,
  verifyingContract: PREDICTION_MARKET_ADDRESS,
  maker: YOUR_ADDRESS,
  makerNonce: BigInt(auction.takerNonce ?? 0),
});
 
// Sign the bid
const signature = await signMakerBid({ 
  privateKey, domain, types, primaryType, message 
});
 
// Submit to relayer
ws.send(JSON.stringify({
  type: 'bid.submit',
  payload: { auctionId, maker, makerWager, makerDeadline, makerSignature, makerNonce },
}));

Customize Your Strategy

The starter is intentionally simple. Extend it by:

  • Sizing bids dynamically based on auction.wager or market conditions
  • Filtering by market using decoded predictedOutcomes to target specific topics
  • Adding risk limits like max total exposure or per-taker rate limits
  • Integrating forecasts to price bids based on your probability estimates

Resources