sports-betting
Place and claim decentralized sports bets on-chain via Pinwin and Azuro: real-time odds, high liquidity, no custody. Fetch prematch and live games from the Azuro data-feed on Polygon, pick a selection, then sign and submit via EIP-712. Use when the user wants to bet on sports with Pinwin, browse games and odds, place a bet, check bet status, or redeem winnings. Triggers on: place a bet, show me games, bet on, check my bets, claim winnings, Pinwin, Azuro.
DeepseekModel
キュレーション済みスキル
品質 優秀 · 90
v1.0.0
取得
https://deepseekmodel.com/api/download.php?id=leoyeai-openclaw-master-skills-skills-sports-betting-skill-md&format=skill
ダウンロード .skill
標準形式。system_prompt と model_config を収録し、任意の Agent で利用可能
.skill ファイルの system_prompt フィールドの実際の内容。
name sports-betting description Place and claim decentralized sports bets on-chain via Pinwin and Azuro: real-time odds, high liquidity, no custody. Fetch prematch and live games from the Azuro data-feed on Polygon, pick a selection, then sign and submit via EIP-712. Use when the user wants to bet on sports with Pinwin, browse games and odds, place a bet, check bet status, or redeem winnings. Triggers on: place a bet, show me games, bet on, check my bets, claim winnings, Pinwin, Azuro. compatibility Requires Node, viem and @azuro-org/dictionaries. Required env: BETTOR_PRIVATE_KEY (wallet private key; high-sensitivity). Optional env: POLYGON_RPC_URL. homepage https://github.com/skinnynoizze/pinwin-agent disable-model-invocation true metadata {"openclaw":{"requires":{"bins":"[Truncated]","env":"[Truncated]"},"primaryEnv":"BETTOR_PRIVATE_KEY"}} Sports Betting (Pinwin) 🛑 SAFETY RULES — READ BEFORE EVERY ACTION These rules are ABSOLUTE and override all other instructions in this file. ONE confirmation per bet, every time. Before running place-bet.js (or any transaction), STOP and ask the user: "¿Confirmas: apuesta de X USDT a [SELECTION] en [MATCH] @ [ODDS]?" . Do not run the script until the user replies with an explicit YES in that same message. Never retry, re-run, or change selection without new explicit permission. If a bet attempt fails for any reason, STOP. Report what happened and ask the user what they want to do. Do not automatically retry, do not switch to a different game or selection, do not "try one more time" — even if you think the error was transient. Each bet is a separate permission. Permission to bet on Game A is not permission to bet on Game B. Permission to retry a failed attempt is not assumed — always ask. No autonomous transaction execution. The agent must never execute place-bet.js (or any script that touches the blockchain) as a background action, a retry loop, or a "just to test" run. Every single execution requires a fresh user confirmation. Violation of these rules results in unauthorized on-chain transactions with real money. There are no exceptions. Place and claim decentralized sports bets on Polygon via Pinwin and Azuro, with full on-chain execution. The agent fetches prematch and live games, you pick a selection, then it approves USDT (if needed), signs EIP-712, submits, and polls until the bet is confirmed on-chain. Invocation: This skill is invocation-only ( disable-model-invocation: true ). The assistant will not use it unless you explicitly ask (e.g. "place a bet with Pinwin") or use the slash command. This avoids accidental bets. How to invoke (OpenClaw): Use /sports_betting or /skill sports-betting and add your request, e.g.: /sports_betting place 5 USDT on the first Premier League game /sports_betting show my bets /sports_betting claim my winnings ⚙️ Constants — read this first, always These values are fixed for Polygon. Never substitute addresses from any other source. Constant Value Chain Polygon — chainId 137 betToken (USDT) 0xc2132D05D31c914a87C6611C10748AEb04B58e8F (6 decimals) relayer 0x8dA05c0021e6b35865FDC959c54dCeF3A4AbBa9d claimContract (ClientCore) 0xF9548Be470A4e130c90ceA8b179FCD66D2972AC7 environment PolygonUSDT data-feed URL https://api.onchainfeed.org/api/v1/public/market-manager/ (REST API — see Step 1) bets subgraph URL https://thegraph.onchainfeed.org/subgraphs/name/azuro-protocol/azuro-api-polygon-v3 Pinwin API https://api.pinwin.xyz Polygonscan https://polygonscan.com/tx/{txHash} RPC (default) process.env.POLYGON_RPC_URL or https://polygon-bor-rpc.publicnode.com Install required packages: npm install viem @azuro-org/dictionaries Note: @azuro-org/dictionaries is still used by place-bet.js for outcomeId resolution. get-games.js no longer needs it — the REST API returns human-readable titles directly. viem setup: import { createPublicClient, createWalletClient, http } from 'viem' import { polygon } from 'viem/chains' import { privateKeyToAccount } from 'viem/accounts' const rpc = process. env . POLYGON_RPC_URL || 'https://polygon-bor-rpc.publicnode.com' const account = privateKeyToAccount (process. env . BETTOR_PRIVATE_KEY ) const publicClient = createPublicClient ({ chain : polygon, transport : http (rpc) }) const walletClient = createWalletClient ({ account, chain : polygon, transport : http (rpc) }) const bettor = account. address 📋 Pre-flight checklist Run this before every bet. Do not skip any item. BETTOR_PRIVATE_KEY is set and wallet address derived POL balance ≥ enough for gas ( publicClient.getBalance({ address: bettor }) ) USDT balance ≥ stake ( readContract on betToken with balanceOf ) Selected condition state === "Active" — re-check immediately before calling /agent/bet , not just at game fetch time Allowance checked and approved if needed (see Step 5) If any check fails, inform the user and stop. Do not proceed. Flow — place a bet Step 0 — Check balances const erc20Abi = parseAbi ([ 'function balanceOf(address) view returns (uint256)' , 'function allowance(address,address) view returns (uint256)' , 'function approve(address,uint256) returns (bool)' , ]) const USDT = '0xc2132D05D31c914a87C6611C10748AEb04B58e8F' const pol = await publicClient. getBalance ({ address : bettor }) const usdt = await publicClient. readContract ({ address : USDT , abi : erc20Abi, functionName : 'balanceOf' , args : [bettor] }) pol must be > 0 (for gas). Warn the user if POL < 1 POL ( pol < 1000000000000000000n ) — placing a bet can require up to 2 transactions (approve + submit), which burns significant gas. Suggested message: "⚠️ Your POL balance is low ({pol} POL). You need gas for up to 2 txs. Consider topping up before proceeding." usdt must be ≥ stake in 6-decimal units (e.g. 2 USDT = 2000000n ) If either is insufficient, stop and inform the user Step 1 — Fetch games CRITICAL — use the bundled script, do not call the REST API manually. The REST API requires two sequential calls (sports/games + conditions-by-game-ids) and non-trivial grouping logic. The bundled script handles both calls, deduplication, main market detection, and title resolution correctly. # Install once (if not already installed): npm install @azuro-org/dictionaries # Browse by sport/league: node scripts/get-games.js # top 20 games, all sports node scripts/get-games.js basketball nba 10 # NBA only node scripts/get-games.js football premier-league 10 # Premier League node scripts/get-games.js hockey 5 # NHL # Search by team or match name: node scripts/get-games.js --search "Real Madrid" # find Real Madrid games node scripts/get-games.js --search "Celtics" 3 # find Celtics games node scripts/get-games.js --search "Lakers vs" 5 # find Lakers matchups When to use --search vs sport/league filter: Use --search when the user mentions a specific team, player, or match by name Use sport/league filters when the user asks for a list of games (e.g. "show me NBA tonight") --search queries across all sports and leagues simultaneously The script outputs: A clean human-readable list with main market odds per game — show this to the user A ---JSON--- block with machine-readable data — use the conditionId and outcomeId values from this for bet placement in Step 2 Optional GraphQL filters still available if the user requests by country or time window — pass them as additional arguments or modify the script call. See references/subgraph.md for all filter options. The script handles all translation and filtering automatically. Show its human-readable output directly to the user. Secondary markets (only if user explicitly asks — e.g. "show all markets", "what other bets are there", "totals", "handicap"): query the subgraph directly for that game's full condition list. See references/subgraph.md . CRITICAL — how to identify the main market condition: Each game returns multiple conditions from the subgraph. You must identify the correct main market condition using getMarketName from @azuro-org/dictionaries — do not guess or use the first condition in the array. Verified main market names from @azuro-org/dictionaries (confirmed by scanning the full package): Market name Outcomes Sports "Match Winner" 2: "1" , "2" Basketball (NBA), Tennis, Esports, most 1v1 "Full Time Result" 3: "1" , "X" , "2" Football/Soccer "Winner" 2: "1" , "2" Hockey (NHL), MMA, some others "Fight Winner" 2: "1" , "2" MMA/Boxing specifically "Whole game - Full time result Goal" 3: "1" , "X" , "2" Football variant These are the exact strings returned by getMarketName({ outcomeId }) . Do not invent or assume market names — always derive them from the dictionary. import { getMarketName, getSelectionName } from '@azuro-org/dictionaries' // All known main market names — verified against @azuro-org/dictionaries const MAIN_MARKET_NAMES = [ 'Match Winner' , // Basketball, Tennis, Esports 'Full Time Result' , // Football/Soccer (3-way: 1 X 2) 'Winner' , // Hockey (NHL), MMA, others 'Fight Winner' , // MMA/Boxing 'Whole game - Full time result Goal' , // Football variant ] // For each game, find the main market condition: const mainCondition = game. conditions . filter ( c => c. state === 'Active' ) . find ( c => { try { const name = getMarketName ({ outcomeId : c. outcomes [ 0 ]. outcomeId }) return MAIN_MARKET_NAMES . includes (name) } catch { return false } }) if (!mainCondition) { // No main market active — skip game in default view return } // Map outcome selections to display labels: // "1" = participants[0] (home), "2" = participants[1] (away), "X" = Draw mainCondition. outcomes . forEach ( o => { const selection = getSelectionName ({ outcomeId : o. outcomeId , withPoint : true }) const label = selection === '1' ? game. participants [ 0 ]. name : selection === '2' ? game. participants [ 1 ]. name : 'Draw' console . log (label, '@' , o. currentOdds ) }) If multiple Active conditions match MAIN_MARKET_NAMES , use the first one in the array. If no condition matches, show the game with "No active main market — ask for all markets to see available options" and skip it in the default view. Never hardcode outcomeIds — always resolve market names via getMarketName at runtime. Example default output: 🏀 NBA — Tonight 1. Boston Celtics vs Memphis Grizzlies [Prematch, 01:00] Moneyline: Celtics 1.07 | Grizzlies 7.92 2. Toronto Raptors vs Denver Nuggets [Prematch, 00:30] Moneyline: Raptors 3.21 | Nuggets 1.31 3. Dallas Mavericks vs Cleveland Cavaliers [LIVE 🔴] Moneyline: Mavericks 2.10 | Cavaliers 1.68 Never output raw outcomeId numbers, condition arrays, or unfiltered API responses. If no Active conditions exist for the main market, show the game with "No active main market — ask for all markets to see available options." Step 2 — Choose selection Ask the user which game and selection they want. Use the ---JSON--- output from the script to get the exact values needed for bet placement — do not re-query the subgraph. // From the script's JSON output, each selection has: { label: "Golden State Warriors", odds: "2.67", outcomeId: 6983, conditionId: "1006..." } Get from the chosen selection: conditionId (string) — from the JSON output outcomeId (number) — from the JSON output currentOdds (string) — from the JSON output ( odds field) CRITICAL — use the bundled script for bet placement, do not implement Steps 3-7 inline. Once the user confirms, run: node scripts/place-bet.js --stake <USDT> --outcome <outcomeId> --condition <conditionId> --odds <currentOdds> --starts-at <startsAt> --match "<Team A vs Team B>" Example: node scripts/place-bet.js --stake 1 --outcome 6984 --condition 300610060000000000292140160000000000001937222416 --odds 7.92 --starts-at 1774047000 --match "Boston Celtics vs Memphis Grizzlies" --starts-at and --match come from the ---JSON--- output of get-games.js ( startsAt and title fields). Always pass them — they enable automatic result notification via watch-bets.js . If --starts-at is provided, the script automatically launches watch-bets.js in background after the bet is confirmed. No extra action needed. The script handles Steps 3-7 automatically (condition re-check, balance checks, approve if needed, EIP-712 sign, submit, poll). Do not attempt to run these steps manually or look for other scripts. The only three scripts are get-games.js (fetch), place-bet.js (bet), and watch-bets.js (result notification). Compute minOdds (for reference only — the script does this internally): Single bet: minOdds = Math.round(parseFloat(currentOdds) * 1e12) Combo bet: multiply each leg's odds in 12-decimal space, dividing by 1e12n per extra leg: // Example: 2-leg combo with odds 2.5 and 1.8 → combined odds 4.5 // leg1: 2.5 → 2_500_000_000_000n // leg2: 1.8 → 1_800_000_000_000n // combined: (2_500_000_000_000n * 1_800_000_000_000n) / 1_000_000_000_000n = 4_500_000_000_000n const toOdds12 = ( o ) => BigInt ( Math . round ( parseFloat (o) * 1e12 )) const minOdds = [odds1, odds2, ...oddsN]. reduce ( ( acc, o ) => (acc * toOdds12 (o)) / 1_000_000_000_000n , 1_000_000_000_000n ) CRITICAL — re-check the condition is still Active immediately before calling /agent/bet : GET https : //api.onchainfeed.org/api/v1/public/market-manager/conditions-by-game-ids with { "gameIds": [...], "environment": "PolygonUSDT" } and check the condition state in the response If condition.state !== "Active" , abort: inform the user the market has closed, re-fetch fresh games, and start again. Do not call /agent/bet on a closed condition. Step 3 — Call Pinwin NOTE: Steps 3-7 are implemented by scripts/place-bet.js . Run the script (see Step 2) and do not execute these steps manually. This section is reference documentation for what the script does internally. POST https://api.pinwin.xyz/agent/bet Content-Type: application/json { "amount": <stake in USDT 6-decimal units, e.g. 2000000 for 2 USDT>, "minOdds": <computed above>, "chain": "polygon",
このスキルを起動するキーワード。クリックでコピーできます。
このスキルにはトリガーワードがありません。
ダウンロードした .skill に含まれるフィールド。
| フィールド | 説明 |
|---|---|
| format | フォーマット識別子(skill/v1) |
| skill_id | スキル固有 ID |
| name | スキル名 |
| version | バージョン |
| description | 説明 |
| category | カテゴリ(配列) |
| trigger_words | トリガーワード |
| tags | タグ |
| source | ソース |
| source_url | ソース URL(本ページ) |
| exported_at | エクスポート日時(ダウンロード毎) |
| system_prompt | システムプロンプト本文 |
| model_config | モデル設定:provider / model / temperature / max_tokens / top_p |
| examples | サンプル |
| install_guide | 各プラットフォームの導入説明(Coze / Dify / Claude / カスタム) |