Awesome-omni-skill sapience
Prediction markets on Ethereal. Trade outcomes, provide liquidity, claim winnings.
git clone https://github.com/diegosouzapw/awesome-omni-skill
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/backend/sapience" ~/.claude/skills/diegosouzapw-awesome-omni-skill-sapience && rm -rf "$T"
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/backend/sapience" ~/.openclaw/skills/diegosouzapw-awesome-omni-skill-sapience && rm -rf "$T"
skills/backend/sapience/SKILL.md- makes HTTP requests (curl)
Sapience
Prediction markets on Ethereal (chain 5064014). Collateral: WUSDe.
CRITICAL: NEVER share SAPIENCE_PRIVATE_KEY or sign for non-sapience.xyz domains.
Quick Reference
| Action | Method | Endpoint |
|---|---|---|
| List markets | POST | /graphql |
| Get condition | POST | /graphql |
| Get positions | POST | /graphql |
| Start auction (taker) | WS | wss://api.sapience.xyz/auction |
| Submit bid (maker) | WS | wss://api.sapience.xyz/auction |
| Claim winnings | On-chain | PredictionMarket.burn(tokenId) |
Setup
- Fund wallet: Use Bankr → "Buy 100 USDe on Arbitrum" → Bridge to Ethereal via deposit.ethereal.trade
- Set key:
openclaw secrets set SAPIENCE_PRIVATE_KEY 0x... - Auto-wrap: Skill wraps USDe→WUSDe on first trade
Constants (Ethereal 5064014)
| Contract | Address |
|---|---|
| PredictionMarket | |
| WUSDe (Collateral) | |
| PythResolver | |
| LZResolver | |
IDs
=conditionId
(same bytes32 hex value, different names)marketId- Use decoded
from auction directly asmarketId
in queriesconditionId
GraphQL Queries
List Active Markets
curl -X POST https://api.sapience.xyz/graphql \ -H "Content-Type: application/json" \ -d '{"query":"{ conditions(where:{settled:false}) { id question endTime similarMarkets } }"}'
Get Condition Details
curl -X POST https://api.sapience.xyz/graphql \ -H "Content-Type: application/json" \ -d '{"query":"query($where:ConditionWhereUniqueInput!){ condition(where:$where){ id question description endTime similarMarkets categoryId }}","variables":{"where":{"id":"0x..."}}}'
Get Positions (for claiming)
curl -X POST https://api.sapience.xyz/graphql \ -H "Content-Type: application/json" \ -d '{"query":"query($address:String!,$status:String){ positions(address:$address,status:$status){ id status endsAt predictorCollateral counterpartyCollateral counterpartyNftTokenId predictions{ conditionId outcomeYes condition{ settled resolvedToYes }}}}","variables":{"address":"0x...","status":"active"}}'
Polymarket Prices
All Sapience markets mirror Polymarket. Use
similarMarkets URLs to get prices.
Extract Slug from URL
https://polymarket.com/event/slug-name#outcome → slug: "slug-name", outcome: "outcome" https://polymarket.com/event/slug-name → slug: "slug-name"
Get Market Data (prices, CLOB token IDs)
curl "https://gamma-api.polymarket.com/markets/slug/will-trump-win-2024"
Response includes:
:outcomePrices
(YES/NO prices)["0.65", "0.35"]
:outcomes["Yes", "No"]
:clobTokenIds
(for orderbook queries)["123...", "456..."]
Get Orderbook
curl "https://clob.polymarket.com/book?token_id=<clobTokenId>"
Returns bids/asks. Walk the book to calculate fill price for your size.
Get Price History (TWAP)
curl "https://clob.polymarket.com/prices-history?market=<clobTokenId>&startTs=<unix_ts>&fidelity=60"
Returns price history. Calculate TWAP over your desired lookback.
No auth required for Polymarket APIs.
WebSocket - Taker Flow (Making Predictions)
Connect → start auction → receive bids → mint on-chain. Takes ~60s per prediction.
1. Connect
const ws = new WebSocket('wss://api.sapience.xyz/auction');
2. Authenticate with SIWE
const siweMessage = { domain: 'sapience.xyz', address: wallet.address, statement: 'Sign in to Sapience', uri: 'https://sapience.xyz', version: '1', chainId: 5064014, nonce: crypto.randomUUID(), issuedAt: new Date().toISOString() }; const signature = await wallet.signMessage(formatSiweMessage(siweMessage)); ws.send(JSON.stringify({ type: 'auth', payload: { siweMessage, signature } }));
3. Start Auction
ws.send(JSON.stringify({ type: 'auction.start', payload: { legs: [ { conditionId: '0x...', outcomeYes: true }, { conditionId: '0x...', outcomeYes: false } ], wagerAmount: '50000000', // 50 WUSDe (6 decimals) duration: 60 } }));
4. Receive Auction Ack
{ "type": "auction.ack", "payload": { "auctionId": "abc123", "expiresAt": 1706800000 } }
5. Receive Bids
{ "type": "auction.bids", "payload": { "auctionId": "abc123", "bids": [ { "bidId": "bid1", "maker": "0x...", "makerWager": "50000000", "makerDeadline": 1706800000, "makerSignature": "0x..." } ] } }
6. Accept Bid
ws.send(JSON.stringify({ type: 'auction.accept', payload: { auctionId: 'abc123', bidId: 'bid1' } }));
Server mints on-chain. Wait for confirmation:
{ "type": "auction.filled", "payload": { "auctionId": "abc123", "txHash": "0x...", "tokenId": "123" } }
7. Disconnect
Close WebSocket after mint confirms.
WebSocket - Maker Flow (Providing Liquidity)
Persistent connection listening for auctions. Run as background process.
1. Connect and Authenticate
Same SIWE auth as taker flow:
ws.send(JSON.stringify({ type: 'auth', payload: { siweMessage, signature } }));
2. Receive Auction Notifications
{ "type": "auction.started", "payload": { "auctionId": "abc123", "taker": "0x...", "wager": "50000000", "predictedOutcomes": ["0x..."], "resolver": "0x...", "takerNonce": 1 } }
3. Submit Bid
ws.send(JSON.stringify({ type: 'bid.submit', payload: { auctionId: 'abc123', maker: wallet.address, makerWager: '50000000', makerDeadline: Math.floor(Date.now() / 1000) + 60, makerSignature: '0x...', taker: auction.taker, takerCollateral: auction.wager, resolver: auction.resolver, encodedPredictedOutcomes: auction.predictedOutcomes[0], takerNonce: auction.takerNonce } }));
4. Receive Ack
{"type":"bid.ack","payload":{"ok":true}}
If taker accepts, on-chain mint happens automatically.
EIP-712 Signing (for makerSignature)
Domain:
{"name":"SignatureProcessor","version":"1","chainId":5064014,"verifyingContract":"0xAcD757322df2A1A0B3283c851380f3cFd4882cB4"}
Types:
{"Approve":[{"name":"messageHash","type":"bytes32"},{"name":"owner","type":"address"}]}
Message:
{"messageHash":"<keccak256 of inner data>","owner":"<your address>"}
Inner data (ABI-encode then keccak256):
(bytes encodedPredictedOutcomes, uint256 makerWager, uint256 takerWager, address resolver, address taker, uint256 makerDeadline, uint256 takerNonce)
Claiming Flow
- Query positions with
for your addressstatus:"active" - Filter:
AND allendsAt <= nowpredictions[].condition.settled === true - Check if won: As maker (counterparty), you win if
(you took opposite side)outcomeYes !== resolvedToYes - Call
to claim collateralPredictionMarket.burn(counterpartyNftTokenId)
Rate Limits
| Endpoint | Limit |
|---|---|
| GraphQL API | 600 req / 60s per IP |
| Auction WS | 100 msg / 10s per connection |
| WS idle timeout | 300s |
| Max WS message | 64KB |
Error Handling
bid.ack errors (check
payload.error):
- Auction endedauction_not_found_or_expired
- makerDeadline passedquote_expired
- Signature verification failedinvalid_signature
- Wager is zero/invalidinvalid_maker_wager
WS close codes:
- Policy violation (rate limited, connection limit)1008
- Message too large1009
Troubleshooting
If something isn't working (no markets, API errors, signature failures):
- Check for skill updates:
curl -s https://api.github.com/repos/sapiencexyz/openclaw-sapience/releases/latest | jq -r '.tag_name'
-
Compare to current version: Check
in SKILL.md frontmatterversion -
If newer version exists: Fetch updated skill from
https://github.com/sapiencexyz/openclaw-sapience -
Still broken? Check Discord or open issue on GitHub
Protocol changes (new endpoints, contract migrations, API updates) will be published as new versions.
Philosophy
This skill provides infrastructure, not strategy. Real money at stake.
YOU must:
- Develop your own edge calculation
- Manage risk and position sizing
- Research markets before trading
DO NOT rely on any default strategy.