crewmind-bets

AI & LLMs
v1.0.0
Benign

> **TL;DR**: Place bets on LLM models competing in CrewMind Arena.

11.3K downloads1.3K installsby @vladthecto

Setup & Installation

Install command

clawhub install vladthecto/crewmind-bets

If the CLI is not installed:

Install command

npx clawhub@latest install vladthecto/crewmind-bets

Or install with OpenClaw CLI:

Install command

openclaw skills install vladthecto/crewmind-bets

or paste the repo link into your assistant's chat

Install command

https://github.com/openclaw/skills/tree/main/skills/vladthecto/crewmind-bets

What This Skill Does

CrewMind Arena is a Solana-based betting platform where users wager SOL on which AI model wins each competition round. Supported models are OpenAI, DeepSeek, Grok, and Gemini. Winners receive their original stake plus a proportional share of the losing pool.

Interacts with the on-chain program directly, so bets and claims can be executed without relying on the CrewMind website UI.

When to Use It

  • Bet SOL on DeepSeek winning the current Arena round
  • Claim winnings after your chosen AI model wins a round
  • Check round status and time remaining before wagering
  • Monitor round finalization to know when rewards are claimable
  • Add more SOL to an existing bet on a model mid-round
View original SKILL.md file
# CrewMind Arena Betting Skill

> **TL;DR**: Place bets on LLM models competing in CrewMind Arena. Bet on which AI wins each round, claim rewards if your model wins.

## Quick Start

```bash
npm install @solana/web3.js @coral-xyz/anchor dotenv
```

## Program Info

| Parameter | Value |
|-----------|-------|
| **Program ID** | `F5eS61Nmt3iDw8RJvvK5DL4skdKUMA637MQtG5hbht3Z` |
| **Network** | Solana Mainnet |
| **Website** | https://crewmind.xyz |

## Ship Index Mapping

| Index | Model |
|-------|-------|
| 0 | OpenAI |
| 1 | DeepSeek |
| 2 | Grok |
| 3 | Gemini |

---

## PDA Seeds

| Account | Seeds |
|---------|-------|
| Config | `["config"]` |
| Round | `["round", config, round_id]` |
| Bet | `["bet", round, user]` |
| Vault | `["vault", round]` |

---

## Instruction Discriminators

| Instruction | Discriminator (bytes) |
|-------------|----------------------|
| `place_bet` | `[222, 62, 67, 220, 63, 166, 126, 33]` |
| `claim` | `[62, 198, 214, 193, 213, 159, 108, 210]` |

---

## Account Structures

### Config Account (120 bytes)

```
Offset  Size  Field
─────────────────────────────────
0       8     discriminator
8       32    admin (Pubkey)
40      32    treasury (Pubkey)
72      8     next_round_id (u64)
80      32    active_round (Pubkey) ← use this!
112     8     active_round_id (u64)
```

### Round Account (190 bytes)

```
Offset  Size  Field
─────────────────────────────────
0       8     discriminator
8       8     id (u64)
16      1     status (u8: 0=Open, 1=Finalized)
17      1     ship_count (u8)
18      1     winner_ship (u8, 255=unset)
19      1     swept (bool)
20      8     start_ts (i64)
28      8     end_ts (i64)
36      8     finalized_ts (i64)
44      8     min_bet (u64)
52      8     max_bet (u64)
60      2     participants (u16)
62      8     total_staked (u64)
70      32    totals_by_ship ([u64; 4])
102     64    weighted_by_ship ([u128; 4])
166     8     losing_pool (u64)
174     16    total_weighted_winners (u128)
```

### Bet Account (96 bytes)

```
Offset  Size  Field
─────────────────────────────────
0       8     discriminator
8       1     initialized (bool)
9       32    round (Pubkey)
41      32    user (Pubkey)
73      1     ship (u8)
74      1     claimed (bool)
75      6     _pad
81      8     total_amount (u64)
89      16    total_weighted (u128)
```

---

## Entrypoint: place_bet

### Goal
Place a bet on a ship (AI model) in the active round.

### Instruction
`place_bet(ship: u8, amount: u64)`

### Accounts (in order)

| # | Account | Signer | Writable | Description |
|---|---------|--------|----------|-------------|
| 0 | user | ✓ | ✓ | Your wallet |
| 1 | config | | | PDA `["config"]` |
| 2 | round | | ✓ | Active round pubkey from config |
| 3 | bet | | ✓ | PDA `["bet", round, user]` |
| 4 | vault | | ✓ | PDA `["vault", round]` |
| 5 | system_program | | | `11111111111111111111111111111111` |

### Constraints
- `ship < ship_count` (usually 4)
- `min_bet <= amount <= max_bet`
- `current_time < end_ts`
- Round status must be `Open` (0)

### Instruction Data Layout
```
Bytes 0-7:   discriminator [222, 62, 67, 220, 63, 166, 126, 33]
Byte 8:     ship (u8)
Bytes 9-16: amount (u64 LE)
```

---

## Entrypoint: claim

### Goal
Claim rewards after round finalization (if your ship won).

### Instruction
`claim()` — no arguments

### Accounts (in order)

| # | Account | Signer | Writable | Description |
|---|---------|--------|----------|-------------|
| 0 | user | ✓ | ✓ | Your wallet |
| 1 | round | | | The finalized round |
| 2 | bet | | ✓ | PDA `["bet", round, user]` |
| 3 | vault | | ✓ | PDA `["vault", round]` |
| 4 | system_program | | | `11111111111111111111111111111111` |

### Constraints
- Round status must be `Finalized` (1)
- Your bet's `ship == winner_ship`
- `claimed == false`

### Instruction Data Layout
```
Bytes 0-7: discriminator [62, 198, 214, 193, 213, 159, 108, 210]
```

---

## Errors

| Code | Name | Description |
|------|------|-------------|
| 6004 | InvalidShip | Ship index >= ship_count |
| 6005 | RoundNotOpen | Round is finalized |
| 6006 | RoundEnded | Past end_ts |
| 6008 | RoundNotFinalized | Can't claim yet |
| 6009 | TooLate | Too late to bet |
| 6011 | InvalidBetAmount | Amount out of bounds |
| 6014 | AlreadyClaimed | Already claimed |
| 6015 | NotAWinner | Your ship didn't win |

---

## Complete JavaScript Example

```javascript
import { Connection, PublicKey, Keypair, Transaction, TransactionInstruction, SystemProgram } from '@solana/web3.js';

const PROGRAM_ID = new PublicKey('F5eS61Nmt3iDw8RJvvK5DL4skdKUMA637MQtG5hbht3Z');
const SHIPS = { openai: 0, deepseek: 1, grok: 2, gemini: 3 };

async function getActiveRound(connection) {
  const [configPda] = PublicKey.findProgramAddressSync([Buffer.from('config')], PROGRAM_ID);
  const configAccount = await connection.getAccountInfo(configPda);
  if (!configAccount) throw new Error('Config not found');

  const activeRound = new PublicKey(configAccount.data.slice(80, 112));
  if (activeRound.equals(PublicKey.default)) throw new Error('No active round');

  return { configPda, activeRound };
}

async function getRoundInfo(connection, roundPubkey) {
  const acc = await connection.getAccountInfo(roundPubkey);
  if (!acc) throw new Error('Round not found');
  const d = acc.data;

  return {
    id: d.readBigUInt64LE(8),
    status: d.readUInt8(16),           // 0=Open, 1=Finalized
    shipCount: d.readUInt8(17),
    winnerShip: d.readUInt8(18),       // 255 if not set
    startTs: d.readBigInt64LE(20),
    endTs: d.readBigInt64LE(28),
    minBet: d.readBigUInt64LE(44),
    maxBet: d.readBigUInt64LE(52),
  };
}

async function placeBet(connection, wallet, shipName, amountSol) {
  const ship = SHIPS[shipName.toLowerCase()];
  const amountLamports = BigInt(Math.floor(amountSol * 1e9));

  const { configPda, activeRound } = await getActiveRound(connection);
  const roundInfo = await getRoundInfo(connection, activeRound);

  // Validations
  if (roundInfo.status !== 0) throw new Error('Round not open');
  if (BigInt(Date.now() / 1000) >= roundInfo.endTs) throw new Error('Round ended');
  if (amountLamports < roundInfo.minBet || amountLamports > roundInfo.maxBet) {
    throw new Error(`Amount must be between ${Number(roundInfo.minBet)/1e9} and ${Number(roundInfo.maxBet)/1e9} SOL`);
  }

  const [betPda] = PublicKey.findProgramAddressSync(
    [Buffer.from('bet'), activeRound.toBuffer(), wallet.publicKey.toBuffer()], PROGRAM_ID
  );
  const [vaultPda] = PublicKey.findProgramAddressSync(
    [Buffer.from('vault'), activeRound.toBuffer()], PROGRAM_ID
  );

  const data = Buffer.concat([
    Buffer.from([222, 62, 67, 220, 63, 166, 126, 33]), // discriminator
    Buffer.from([ship]),                                // ship u8
    (() => { const b = Buffer.alloc(8); b.writeBigUInt64LE(amountLamports); return b; })()
  ]);

  const ix = new TransactionInstruction({
    keys: [
      { pubkey: wallet.publicKey, isSigner: true, isWritable: true },
      { pubkey: configPda, isSigner: false, isWritable: false },
      { pubkey: activeRound, isSigner: false, isWritable: true },
      { pubkey: betPda, isSigner: false, isWritable: true },
      { pubkey: vaultPda, isSigner: false, isWritable: true },
      { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
    ],
    programId: PROGRAM_ID,
    data,
  });

  const tx = new Transaction().add(ix);
  tx.feePayer = wallet.publicKey;
  tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
  tx.sign(wallet);

  return await connection.sendRawTransaction(tx.serialize());
}

async function claim(connection, wallet, roundPubkey) {
  const roundInfo = await getRoundInfo(connection, roundPubkey);
  if (roundInfo.status !== 1) throw new Error('Round not finalized yet');

  const [betPda] = PublicKey.findProgramAddressSync(
    [Buffer.from('bet'), roundPubkey.toBuffer(), wallet.publicKey.toBuffer()], PROGRAM_ID
  );
  const [vaultPda] = PublicKey.findProgramAddressSync(
    [Buffer.from('vault'), roundPubkey.toBuffer()], PROGRAM_ID
  );

  const data = Buffer.from([62, 198, 214, 193, 213, 159, 108, 210]); // claim discriminator

  const ix = new TransactionInstruction({
    keys: [
      { pubkey: wallet.publicKey, isSigner: true, isWritable: true },
      { pubkey: roundPubkey, isSigner: false, isWritable: false },
      { pubkey: betPda, isSigner: false, isWritable: true },
      { pubkey: vaultPda, isSigner: false, isWritable: true },
      { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
    ],
    programId: PROGRAM_ID,
    data,
  });

  const tx = new Transaction().add(ix);
  tx.feePayer = wallet.publicKey;
  tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
  tx.sign(wallet);

  return await connection.sendRawTransaction(tx.serialize());
}

// Usage:
// const connection = new Connection('https://api.mainnet-beta.solana.com', 'confirmed');
// const wallet = Keypair.fromSecretKey(...);
// await placeBet(connection, wallet, 'deepseek', 0.01);
```

---

## Workflow Summary

```
1. GET ACTIVE ROUND
   └─> Read Config PDA → get active_round pubkey

2. CHECK ROUND STATUS
   └─> Read Round account → verify status=0 (Open), check end_ts

3. PLACE BET
   └─> Call place_bet(ship, amount)
   └─> Creates Bet PDA, transfers SOL to Vault

4. WAIT FOR ROUND TO END
   └─> Monitor: current_time > end_ts

5. WAIT FOR FINALIZATION
   └─> Monitor: Round.status == 1 (Finalized)
   └─> Check: Round.winner_ship

6. CLAIM (if won)
   └─> Call claim() if your ship == winner_ship
   └─> Receives: original_bet + share_of_losing_pool
```

---

## Safety Rules

- Never bet more than `max_bet`
- Check `end_ts` before betting (avoid TooLate error)
- Only one bet per round per user (but can add to existing bet)
- Always verify round is `Open` before betting
- Always verify round is `Finalized` before claiming
- Keep SOL for transaction fees (~0.002 SOL recommended buffer)

Example Workflow

Here's how your AI assistant might use this skill in practice.

INPUT

User asks: Bet SOL on DeepSeek winning the current Arena round

AGENT
  1. 1Bet SOL on DeepSeek winning the current Arena round
  2. 2Claim winnings after your chosen AI model wins a round
  3. 3Check round status and time remaining before wagering
  4. 4Monitor round finalization to know when rewards are claimable
  5. 5Add more SOL to an existing bet on a model mid-round
OUTPUT
> **TL;DR**: Place bets on LLM models competing in CrewMind Arena.

Share this skill

Security Audits

VirusTotalBenign
OpenClawBenign
View full report

These signals reflect official OpenClaw status values. A Suspicious status means the skill should be used with extra caution.

Details

LanguageMarkdown
Last updatedFeb 28, 2026