Auction Relayer API
The Auction WebSocket connects makers and takers for short-lived auctions. Makers announce an auction; takers submit bids; the relayer validates and forwards bids back to the maker.
- Maker →
auction.start
→ relayer acks withauction.ack
and broadcastsauction.started
- Taker →
bid.submit
→ relayer acks withbid.ack
and streamsauction.bids
to the maker
Endpoints
- Production:
wss://api.sapience.xyz/auction
(confirm base URL) - Local (monorepo):
ws://localhost:3001/auction
Quick start
Minimal Maker flow (Node)
import WebSocket from 'ws';
const ws = new WebSocket('ws://localhost:3001/auction');
ws.on('open', () => {
ws.send(JSON.stringify({
type: 'auction.start',
payload: {
maker: '0xMaker123...',
wager: '1000000000000000000',
resolver: '0xResolver456...',
predictedOutcomes: ['0xdeadbeef']
},
}));
});
ws.on('message', (data) => {
const msg = JSON.parse(String(data));
if (msg.type === 'auction.ack') {
console.log('started auctionId=', msg.payload.auctionId);
}
if (msg.type === 'auction.bids') {
const bids = msg.payload.bids;
// choose best non-expired by takerWager (highest first)
bids.sort((a, b) => BigInt(b.takerWager) - BigInt(a.takerWager) > 0n ? 1 : -1);
console.log('top bid:', bids[0]);
}
});
Minimal Taker flow (Browser/Node)
const ws = new WebSocket('ws://localhost:3001/auction');
ws.onmessage = (ev) => {
const msg = JSON.parse(String(ev.data));
if (msg.type === 'auction.started') {
const auction = msg.payload;
const now = Math.floor(Date.now()/1000);
const bid = {
type: 'bid.submit',
payload: {
auctionId: auction.auctionId,
taker: '0xTaker789...',
takerWager: (BigInt(auction.wager) / 2n).toString(),
takerDeadline: now + 60,
takerSignature: '0x...' // signature over typed payload (see Reference)
}
};
ws.send(JSON.stringify(bid));
}
};
Message lifecycle
- Maker sends
auction.start
withmaker
,wager
,resolver
,predictedOutcomes[]
. - Relayer responds to the same socket with
auction.ack { auctionId }
and broadcastsauction.started
(with the same payload plusauctionId
) to all connected clients. - Takers send
bid.submit
withauctionId
,taker
,takerWager
,takerDeadline
,takerSignature
. - Relayer replies to the bidding socket with
bid.ack { error? }
and streamsauction.bids { bids[] }
to the maker’s subscribed socket for that auction.
- Makers are automatically subscribed to their auction’s channel upon
auction.start
. auction.bids
is broadcast only to subscribers of thatauctionId
.- Auctions are short-lived (about 60 seconds) and expire automatically.
Validation (high level)
- Auction: positive
wager
, ≥1predictedOutcomes
, validresolver
, validmaker
address - Bid:
takerDeadline
in the future, positivetakerWager
, valid hextakerSignature
format - Optional strict signature verification may be performed against
PredictionMarket.sol
using EIP-712 (see Reference for the typed payload and domain).
Limits and closes
- Rate limit: 100 messages per 10s window; violations close with code
1008
and reasonrate_limited
- Max message size: 64,000 bytes; violations close with code
1009
and reasonmessage_too_large
Selecting the best bid
Relayer keeps all valid bids for the auction. The UI or maker should select the best non-expired bid, typically the highest takerWager
.
Next steps
- Read the full message schemas and typed-signature details in the Reference: Auction Relayer Reference
- See a working taker bot in
packages/api/src/auction/botExample.ts
for practical integration patterns.