|
| 1 | +--- |
| 2 | +name: playing-lingo |
| 3 | +description: Play the Lingo word guessing game on Abstract chain — practice mode, ETH duel betting, stickers, achievements, referrals, and jackpots via MCP tools. Use when a user wants to play Lingo, start a practice game, create or join a duel, guess a word, check match status, deposit or withdraw ETH for duels, view stats or leaderboard, collect stickers, claim achievements, do daily check-in, use referral codes, or check the jackpot. Trigger for requests mentioning Lingo, Wordle duel, word game, practice game, duel bet, guess word, match status, ETH deposit for game, withdraw winnings, player stats, leaderboard, stickers, achievements, check-in, referral, or jackpot. |
| 4 | +--- |
| 5 | + |
| 6 | +# Playing Lingo |
| 7 | + |
| 8 | +Lingo is a competitive Wordle-style word guessing game on the Abstract blockchain. Players guess 5-letter words, |
| 9 | +receive per-tile feedback (green/yellow/gray), and compete in practice mode (free, vs bot) or ETH-betting duels (1v1 |
| 10 | +PvP). The game features a jackpot system, LP-based ranking, achievements, stickers, daily check-ins, and referrals. |
| 11 | + |
| 12 | +## Operating Rules |
| 13 | + |
| 14 | +- **Authentication required.** Most MCP tools require a Bearer token. Generate one at |
| 15 | + [https://witty.game/lingo/mcp-token](https://witty.game/lingo/mcp-token) using the same wallet your agent uses, then |
| 16 | + add the MCP server to your client. |
| 17 | +- **Start guessing immediately.** After creating a duel, submit guesses right away — even if the match status is |
| 18 | + "waiting" (no opponent yet). Do NOT wait for an opponent to join. |
| 19 | +- **Deposit before dueling.** You must complete an on-chain `depositETH` transaction to the SignedVault contract BEFORE |
| 20 | + calling `lingo_duel_create`. Read [references/signed-vault-contract.md](./references/signed-vault-contract.md) for |
| 21 | + the full deposit flow. |
| 22 | +- **Withdraw after winning.** When you win a duel, the match result contains a `withdrawal_signature`. Use it to call |
| 23 | + `withdrawETH` on-chain to claim your ETH. Jackpot wins require a separate withdrawal. |
| 24 | +- **Preview on-chain transactions.** Always use `--dry-run` before `--execute` for any contract interaction. |
| 25 | +- Read [references/mcp-tools.md](./references/mcp-tools.md) for the complete tool reference. |
| 26 | +- Read [references/game-rules.md](./references/game-rules.md) for detailed game rules, tiers, and economy. |
| 27 | + |
| 28 | +## MCP Setup |
| 29 | + |
| 30 | +### 0. Set up your agent wallet |
| 31 | + |
| 32 | +Your agent needs access to a wallet on Abstract chain to deposit ETH and play duels. If you don't have one yet, the |
| 33 | +[AGW CLI](https://github.com/Abstract-Foundation/agw-cli) is one easy way to set up a wallet your agent uses. |
| 34 | + |
| 35 | +### 1. Generate a token |
| 36 | + |
| 37 | +Visit [https://witty.game/lingo/mcp-token](https://witty.game/lingo/mcp-token) and generate an MCP access token. |
| 38 | + |
| 39 | +**Important:** You must log in with the **same wallet your agent uses** (the AGW wallet). If the token is generated from |
| 40 | +a different wallet, deposits, withdrawals, and duel operations will fail because the on-chain wallet won't match the |
| 41 | +authenticated player account. |
| 42 | + |
| 43 | +### 2. Add the MCP server |
| 44 | + |
| 45 | +**Claude Code (CLI / Desktop):** |
| 46 | + |
| 47 | +```bash |
| 48 | +claude mcp add --transport http --scope user lingo https://api.lingo.witty.game/mcp --header "Authorization: Bearer <YOUR_TOKEN>" |
| 49 | +``` |
| 50 | + |
| 51 | +**Claude Desktop (manual config — `claude_desktop_config.json`):** |
| 52 | + |
| 53 | +```json |
| 54 | +{ |
| 55 | + "mcpServers": { |
| 56 | + "lingo": { |
| 57 | + "url": "https://api.lingo.witty.game/mcp", |
| 58 | + "headers": { |
| 59 | + "Authorization": "Bearer <YOUR_TOKEN>" |
| 60 | + } |
| 61 | + } |
| 62 | + } |
| 63 | +} |
| 64 | +``` |
| 65 | + |
| 66 | +**Cursor / other MCP clients:** |
| 67 | + |
| 68 | +| Property | Value | |
| 69 | +|----------|-----------------------------------------------| |
| 70 | +| URL | `https://api.lingo.witty.game/mcp` | |
| 71 | +| Method | `POST` | |
| 72 | +| Header | `Authorization: Bearer <YOUR_TOKEN>` | |
| 73 | + |
| 74 | +Replace `<YOUR_TOKEN>` with the token from step 1. |
| 75 | + |
| 76 | +## MCP Server |
| 77 | + |
| 78 | +| Property | Value | |
| 79 | +|----------|-----------------------------------------------| |
| 80 | +| Endpoint | `https://api.lingo.witty.game/mcp` | |
| 81 | +| Protocol | MCP (Model Context Protocol) | |
| 82 | +| Auth | `Authorization: Bearer <accessToken>` | |
| 83 | + |
| 84 | +The MCP server exposes tools (actions) and resources (read-only data): |
| 85 | + |
| 86 | +**Resources** (read via MCP `resources/read`): |
| 87 | +- `lingo://rules/game` — game rules, mechanics, winner determination |
| 88 | +- `lingo://rules/tiers` — betting tier configuration and fee breakdown |
| 89 | +- `lingo://rules/ranks` — LP rank thresholds (Bronze/Silver/Gold) |
| 90 | +- `lingo://contracts/chain-info` — Abstract chain ID, RPC, explorer |
| 91 | +- `lingo://contracts/signed-vault` — SignedVault contract address, resolver, full ABI |
| 92 | +- `lingo://contracts/deposit-guide` — step-by-step ETH deposit instructions |
| 93 | +- `lingo://contracts/withdraw-guide` — step-by-step ETH withdrawal instructions |
| 94 | +- `lingo://contracts/subgraph` — subgraph URL, schema, example GraphQL queries |
| 95 | + |
| 96 | +## Betting Tiers |
| 97 | + |
| 98 | +| Tier | Bet | Winner Gets | Gem Reward | |
| 99 | +|---------|-----------|-------------|------------| |
| 100 | +| casual | 0.001 ETH | 0.0019 ETH | 10 gems | |
| 101 | +| shrimp | 0.01 ETH | 0.019 ETH | 50 gems | |
| 102 | +| whale | 0.1 ETH | 0.19 ETH | 250 gems | |
| 103 | + |
| 104 | +Fee: 5% total (2.5% jackpot + 2.5% protocol). Both players earn gems regardless of outcome. |
| 105 | + |
| 106 | +## Contract |
| 107 | + |
| 108 | +| Property | Value | |
| 109 | +|--------------------|----------------------------------------------| |
| 110 | +| SignedVault | `0xF5005cCA582Cb510D15d4D025F78C9258ec07F4b` | |
| 111 | +| Network | Abstract Mainnet (chain ID 2741) | |
| 112 | +| Resolver Address | `0xde27F91F4A1CA98AfD519315432424b7d0346e3C` | |
| 113 | +| ETH Token Address | `0x0000000000000000000000000000000000000000` (native ETH sentinel) | |
| 114 | +| Subgraph URL | `https://api.goldsky.com/api/public/project_cmgz8pxdm000i5ep21i0oazas/subgraphs/signed-vault-subgraph-abstract/latest/gn` | |
| 115 | +| Lingo App ID | `223` (for Abstract Portal voting) | |
| 116 | + |
| 117 | +These addresses and the full ABI are also available at runtime via the MCP resource `lingo://contracts/signed-vault`. |
| 118 | +The subgraph URL and example queries are available via `lingo://contracts/subgraph`. |
| 119 | + |
| 120 | +## ABI Format |
| 121 | + |
| 122 | +The AGW CLI requires full JSON ABI objects, not human-readable strings. Every `abi` array element must be an object with |
| 123 | +`type`, `name`, `inputs`, `outputs`, and `stateMutability` fields. |
| 124 | + |
| 125 | +## Task Map |
| 126 | + |
| 127 | +### Play a practice game (free) |
| 128 | + |
| 129 | +``` |
| 130 | +1. Call lingo_practice_start → returns session_id and word length |
| 131 | +2. Call lingo_practice_guess with session_id and a 5-letter word |
| 132 | +3. Read the feedback: green (right letter, right spot), yellow (right letter, wrong spot), gray (not in word) |
| 133 | +4. Repeat guesses (up to 6 total) using feedback to narrow down the answer |
| 134 | +5. The bot solves on turn 4 — try to solve in 3 or fewer turns to win |
| 135 | +``` |
| 136 | + |
| 137 | +### Play a duel (ETH betting) |
| 138 | + |
| 139 | +``` |
| 140 | +1. Choose a tier: casual (0.001 ETH), shrimp (0.01 ETH), whale (0.1 ETH) |
| 141 | +2. Deposit ETH on-chain: |
| 142 | + - Pick a random unused nonce (e.g., current unix timestamp) |
| 143 | + - Call SignedVault.depositETH(resolver, nonce) with value = tier bet amount |
| 144 | + - Wait for confirmation |
| 145 | +3. Call lingo_duel_create with tier and deposit_nonce |
| 146 | + - For private rooms: set is_private=true (returns invite_code) |
| 147 | + - To join a private room: pass invite_code |
| 148 | +4. Start guessing immediately with lingo_duel_guess — do NOT wait for an opponent |
| 149 | +5. Use tile feedback to solve the word in as few turns as possible |
| 150 | +6. When the match completes, call lingo_duel_status to get the result |
| 151 | +7. If you won: |
| 152 | + - Call SignedVault.withdrawETH using withdrawal_signature from the match result |
| 153 | + - If you solved on turn 1 (jackpot!), make a separate withdrawETH call with the jackpot fields |
| 154 | +``` |
| 155 | + |
| 156 | +### Check match status |
| 157 | + |
| 158 | +``` |
| 159 | +Call lingo_duel_status with match_id |
| 160 | +- Opponent guesses are hidden until you finish your turns |
| 161 | +- Answer words are hidden until the match completes |
| 162 | +- Winner gets withdrawal_signature, withdrawal_nonce, withdrawal_deadline in the response |
| 163 | +``` |
| 164 | + |
| 165 | +### Scan history and auto-withdraw unclaimed winnings |
| 166 | + |
| 167 | +When browsing duel history (`lingo_duel_history`), proactively check for completed matches where the player won |
| 168 | +but hasn't withdrawn on-chain yet. Withdraw any unclaimed winnings on the spot. |
| 169 | + |
| 170 | +``` |
| 171 | +1. Call lingo_duel_history (paginate through all pages if needed) |
| 172 | +2. For each match where is_winner == true and withdrawal_signature exists: |
| 173 | + a. Extract the nonce from withdrawal_signature.nonce |
| 174 | + b. Call SignedVault.usedNonces(resolver, nonce) on-chain to check if already withdrawn: |
| 175 | + agw contract write --json '{ |
| 176 | + "address": "0xF5005cCA582Cb510D15d4D025F78C9258ec07F4b", |
| 177 | + "abi": [{"type":"function","name":"usedNonces","stateMutability":"view","inputs":[{"name":"resolver","type":"address"},{"name":"nonce","type":"uint256"}],"outputs":[{"name":"used","type":"bool"}]}], |
| 178 | + "functionName": "usedNonces", |
| 179 | + "args": ["0xde27F91F4A1CA98AfD519315432424b7d0346e3C", "<NONCE>"] |
| 180 | + }' --dry-run |
| 181 | + c. If usedNonces returns false → the withdrawal is unclaimed. Execute withdrawETH: |
| 182 | + agw contract write --json '{ |
| 183 | + "address": "0xF5005cCA582Cb510D15d4D025F78C9258ec07F4b", |
| 184 | + "abi": [{"type":"function","name":"withdrawETH","stateMutability":"nonpayable","inputs":[{"name":"user","type":"address"},{"name":"amount","type":"uint256"},{"name":"resolver","type":"address"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"},{"name":"signature","type":"bytes"}],"outputs":[]}], |
| 185 | + "functionName": "withdrawETH", |
| 186 | + "args": ["<USER>", "<AMOUNT>", "0xde27F91F4A1CA98AfD519315432424b7d0346e3C", "<NONCE>", "<DEADLINE>", "<SIGNATURE>"] |
| 187 | + }' --dry-run |
| 188 | + All values come directly from the withdrawal_signature object in the match result. |
| 189 | + d. Same check for jackpot_withdrawal_signature if jackpot_amount is present. |
| 190 | +3. Report which matches were already claimed and which were newly withdrawn. |
| 191 | +``` |
| 192 | + |
| 193 | +**Tip:** This is useful as a periodic sweep — winnings don't expire (deadline is ~100 years), so unclaimed |
| 194 | +withdrawals stay valid indefinitely, but it's better to claim them sooner. |
| 195 | + |
| 196 | +### Join a waiting public match |
| 197 | + |
| 198 | +``` |
| 199 | +1. Call lingo_duel_waiting with the tier to see available matches |
| 200 | +2. Deposit ETH on-chain for the chosen tier |
| 201 | +3. Call lingo_duel_create with the tier — matchmaking pairs you with a waiting opponent |
| 202 | +``` |
| 203 | + |
| 204 | +### Deposit ETH on-chain (before dueling) |
| 205 | + |
| 206 | +```bash |
| 207 | +agw contract write --json '{ |
| 208 | + "address": "0xF5005cCA582Cb510D15d4D025F78C9258ec07F4b", |
| 209 | + "abi": [{"type":"function","name":"depositETH","stateMutability":"payable","inputs":[{"name":"resolver","type":"address"},{"name":"nonce","type":"uint256"}],"outputs":[]}], |
| 210 | + "functionName": "depositETH", |
| 211 | + "args": ["0xde27F91F4A1CA98AfD519315432424b7d0346e3C", "<NONCE>"], |
| 212 | + "value": "<BET_AMOUNT_WEI>" |
| 213 | +}' --dry-run |
| 214 | +``` |
| 215 | + |
| 216 | +Replace: |
| 217 | +- `<NONCE>` — a random unused uint256 (e.g., current unix timestamp) |
| 218 | +- `<BET_AMOUNT_WEI>` — casual: `1000000000000000`, shrimp: `10000000000000000`, whale: `100000000000000000` |
| 219 | + |
| 220 | +Execute after confirming the preview: replace `--dry-run` with `--execute`. |
| 221 | + |
| 222 | +### Withdraw ETH winnings (after winning a duel) |
| 223 | + |
| 224 | +```bash |
| 225 | +agw contract write --json '{ |
| 226 | + "address": "0xF5005cCA582Cb510D15d4D025F78C9258ec07F4b", |
| 227 | + "abi": [{"type":"function","name":"withdrawETH","stateMutability":"nonpayable","inputs":[{"name":"user","type":"address"},{"name":"amount","type":"uint256"},{"name":"resolver","type":"address"},{"name":"nonce","type":"uint256"},{"name":"deadline","type":"uint256"},{"name":"signature","type":"bytes"}],"outputs":[]}], |
| 228 | + "functionName": "withdrawETH", |
| 229 | + "args": ["<YOUR_ADDRESS>", "<WINNER_REWARD_WEI>", "0xde27F91F4A1CA98AfD519315432424b7d0346e3C", "<WITHDRAWAL_NONCE>", "<WITHDRAWAL_DEADLINE>", "<WITHDRAWAL_SIGNATURE>"] |
| 230 | +}' --dry-run |
| 231 | +``` |
| 232 | + |
| 233 | +All values (`withdrawal_nonce`, `withdrawal_deadline`, `withdrawal_signature`, reward amount) come from the |
| 234 | +`lingo_duel_status` response after winning. |
| 235 | + |
| 236 | +### Verify a deposit on-chain |
| 237 | + |
| 238 | +```bash |
| 239 | +agw contract write --json '{ |
| 240 | + "address": "0xF5005cCA582Cb510D15d4D025F78C9258ec07F4b", |
| 241 | + "abi": [{"type":"function","name":"getDeposit","stateMutability":"view","inputs":[{"name":"user","type":"address"},{"name":"token","type":"address"},{"name":"resolver","type":"address"},{"name":"nonce","type":"uint256"}],"outputs":[{"name":"amount","type":"uint256"}]}], |
| 242 | + "functionName": "getDeposit", |
| 243 | + "args": ["<YOUR_ADDRESS>", "0x0000000000000000000000000000000000000000", "0xde27F91F4A1CA98AfD519315432424b7d0346e3C", "<NONCE>"] |
| 244 | +}' --dry-run |
| 245 | +``` |
| 246 | + |
| 247 | +Use `0x0000000000000000000000000000000000000000` as the token address for ETH deposits. |
| 248 | + |
| 249 | +### Daily check-in |
| 250 | + |
| 251 | +``` |
| 252 | +Call lingo_checkin with today's date (YYYY-MM-DD format) |
| 253 | +Streak bonus: 1d=10, 2d=20, 3d=30, 4d=40, 5d+=50 gems. Missing a day resets streak. |
| 254 | +``` |
| 255 | + |
| 256 | +### View stats and leaderboard |
| 257 | + |
| 258 | +``` |
| 259 | +- lingo_player_stats — your full stats (wins, losses, ETH, LP, rank, gems, streaks) |
| 260 | +- lingo_player_profile — your or another player's profile with recent matches |
| 261 | +- lingo_leaderboard — LP rankings (no auth required) |
| 262 | +``` |
| 263 | + |
| 264 | +### Collect and manage stickers |
| 265 | + |
| 266 | +``` |
| 267 | +- lingo_purchase_sticker_pack — buy a random sticker for 200 gems |
| 268 | +- lingo_my_stickers — view owned stickers |
| 269 | +- lingo_upgrade_sticker — combine duplicates to upgrade level |
| 270 | +- lingo_set_pfp — set a sticker as profile picture |
| 271 | +``` |
| 272 | + |
| 273 | +### Claim achievements |
| 274 | + |
| 275 | +``` |
| 276 | +1. Call lingo_achievements to see all achievements and unlock status |
| 277 | +2. Call lingo_claim_achievement with the key (e.g., "first_win") to claim gems |
| 278 | +``` |
| 279 | + |
| 280 | +### Use referral codes |
| 281 | + |
| 282 | +``` |
| 283 | +- lingo_apply_referral — apply someone's referral code (one-time) |
| 284 | +- lingo_referral_dashboard — view your referral earnings |
| 285 | +- lingo_referral_withdraw — withdraw accumulated referral earnings |
| 286 | +``` |
| 287 | + |
| 288 | +### Check jackpot |
| 289 | + |
| 290 | +``` |
| 291 | +- lingo_jackpot_pool — current jackpot amount (no auth) |
| 292 | +- lingo_jackpot_history — past jackpot winners (no auth) |
| 293 | +The jackpot is won by solving a duel word on turn 1. |
| 294 | +``` |
| 295 | + |
| 296 | +### Claim upvote reward |
| 297 | + |
| 298 | +``` |
| 299 | +After voting for Lingo on the Abstract Portal (via the upvoting-on-abstract skill), |
| 300 | +call lingo_upvote_claim with the epoch number to receive 50 gems. |
| 301 | +``` |
| 302 | + |
| 303 | +## Wordle Strategy Tips |
| 304 | + |
| 305 | +- **Start with vowel-rich words** like CRANE, SLATE, AUDIO, RAISE to maximize information. |
| 306 | +- **Use feedback aggressively**: eliminate gray letters, lock green letters, reposition yellow letters. |
| 307 | +- **Green tiles matter even after solving**: in duels, tiebreakers count total green tiles across all guesses. So even |
| 308 | + if you know the answer, consider the quality of your earlier guesses. |
| 309 | +- **Turn 1 solve wins the jackpot**: if you're feeling lucky, guess a common word on turn 1 in a duel. |
| 310 | + |
| 311 | +## Error Handling |
| 312 | + |
| 313 | +| Error Message | Cause | Fix | |
| 314 | +|---------------------------------|----------------------------------------------|-------------------------------------------------| |
| 315 | +| `Login required` | Missing or invalid Authorization header | Add `Authorization: Bearer <token>` to headers | |
| 316 | +| `Player is busy` | Player row locked by concurrent request | Retry after a short delay | |
| 317 | +| `Player not found` | Invalid player ID or token | Re-authenticate | |
| 318 | +| `Match not found` | Invalid match_id | Check match_id from create/history response | |
| 319 | +| `Match already completed` | Trying to guess on a finished match | Check status and start a new match | |
| 320 | +| `Invalid word` | Word not in dictionary | Use a valid 5-letter English word | |
| 321 | +| `Already guessed this word` | Duplicate guess in same session | Try a different word | |
| 322 | +| `Maximum guesses reached` | Used all 6 guesses | Game over — check result | |
| 323 | +| `Deposit not found` | Nonce not found on-chain | Verify deposit transaction confirmed | |
| 324 | +| `Already checked in today` | Duplicate daily check-in | Wait until tomorrow | |
| 325 | + |
| 326 | +## Escalation |
| 327 | + |
| 328 | +- Route on-chain deposit/withdrawal to `executing-agw-transactions`. |
| 329 | +- Route wallet balance checks to `reading-agw-wallet`. |
| 330 | +- Route Abstract Portal voting to `upvoting-on-abstract`. |
| 331 | +- Route app discovery to `discovering-abstract-portal`. |
| 332 | +- Route AGW session setup to `authenticating-with-agw`. |
0 commit comments