Jump to related tools in the same category or review the original source on GitHub.

AI & LLMs @vladthecto Updated 7/16/2026 2,284 downloads 1 stars Security: Pass

Crewmind Bets OpenClaw Plugin & Skill | ClawHub

Looking to integrate Crewmind Bets into your AI workflows? This free OpenClaw plugin from ClawHub helps you automate ai & llms tasks instantly, without having to write custom tools from scratch.

What this skill does

# 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)

Install

ClawHub CLI
openclaw skills install @vladthecto/crewmind-bets
Node.js (npx)
npx clawhub@latest install crewmind-bets

Full SKILL.md

Open original

SKILL.md content below is scrollable.

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

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

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)
ClawHub Registry URL: https://clawhub.ai/vladthecto/skills/crewmind-bets

Related skills

If this matches your use case, these are close alternatives in the same category.