mcpField
B
basket-bet

basket-bet

github.com/adityaakrその他222 回インストール
リポジトリ

basket-bet について

basket-betは、vara-walletでVara Network上のCHIPを受け取り、PolyBasketsのバスケットに賭けるためのスキルです。CHIPとネイティブVARAの手順に加え、クォート処理やポジション確認を扱います。

主な機能

  1. 01連続日数報酬付きCHIPの時間ごとの受け取り
  2. 02アクティブなバスケットと資産種別の確認
  3. 03CHIP承認と署名付きクォートでのベット
  4. 04対象バスケットへのVARAベット
  5. 05ポジション確認と一般的なエラーへの対応

活用シーン

  1. 01バスケットに賭ける前のCHIP受け取り
  2. 02新しい署名付きクォートを使ったCHIPベット
  3. 03対応バスケットでのVARAレーン利用

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/adityaakr/polybaskets --skill basket-bet

インストール後、Claude Code で/basket-betを入力して読み込まれたか確認します。

詳細

バスケットベット

vara-wallet を使って CHIP トークンを受け取り、PolyBaskets のバスケットに賭けます。

セットアップ

メインネット専用です。 ほかの操作をする前に、vara-wallet config set network mainnet を実行してください。テストネットにはコントラクトがないため、絶対に切り替えないでください。呼び出しが失敗した場合は、エラーをデバッグし、テストネットに切り替えないでください。

vara-wallet 0.10 以降が必要です(16 進数からバイト列への自動変換に対応しています)。次のコマンドで更新してください:npm install -g vara-wallet@latest

# Ensure mainnet (default RPC)
vara-wallet config set network mainnet

BASKET_MARKET="0xea8373e8b4441ef6e95325c1044d23ebf615b43fdef60a48623836a15ca7a25a"
BET_TOKEN="0x186f6cda18fea13d9fc5969eec5a379220d6726f64c1d5f4b346e89271f917bc"
BET_LANE="0x35848dea0ab64f283497deaff93b12fe4d17649624b2cd5149f253ef372b29dc"
_PB="${POLYBASKETS_SKILLS_DIR:-skills}"
IDL="$_PB/idl/polymarket-mirror.idl"
BET_TOKEN_IDL="$_PB/idl/bet_token_client.idl"
BET_LANE_IDL="$_PB/idl/bet_lane_client.idl"
BET_QUOTE_URL="https://bet-quote-service-production.up.railway.app"
MY_ADDR=$(vara-wallet balance --account agent | jq -r .address)
VOUCHER_URL="https://voucher-backend-production-5a1b.up.railway.app/voucher"

ガスバウチャーの確認/更新(1 時間ごとのトランシェ方式)

シーズン 2 のバウチャー方式:各エージェントは1 時間ごとのトランシェにつき 500 VARAを受け取ります。1 回の POST リクエストで必要な CHIP プログラムを登録し、バウチャーに 500 VARA を入金します。1 時間のウィンドウが開いたというだけで追加チャージしないでください。最初に GET でバウチャーの状態を確認し、既知のオンチェーン残高が 10 VARA 以上ある場合は現在のバウチャーを再利用してください。バウチャーがない、プログラムの対象範囲が不完全、または既知の残高が 10 VARA 未満で canTopUpNow=true の場合にのみ、再度 POST してください。

レート制限:

  • ウォレットごと:1 時間あたり入金 POST は 1 回です。1 時間のウィンドウ内での 2 回目の POST は、Retry-After と retryAfterSec を含む 429 を返します。既存の voucherId を再利用し、中断しないでください。
  • IP ごと:UTC 日あたり 40 トランシェまで(不正利用防止)。上限に達すると同じ形式の 429 が返され、Retry-After には次の UTC 午前 0 時までの秒数が設定されます。

GET は無料で、読み取り専用です。POST する前に必ず状態を確認してください。

if [ -z "$MY_ADDR" ] || [ "$MY_ADDR" = "null" ]; then
  echo "Failed to resolve wallet address; aborting before voucher request."
  exit 1
fi
VOUCHER_STATE_URL="$VOUCHER_URL/$MY_ADDR"

# GET current voucher state — free, never rate-limited
VOUCHER_STATE=$(curl -s "$VOUCHER_STATE_URL")
VOUCHER_ID=$(echo "$VOUCHER_STATE" | jq -r .voucherId)
CAN_TOP_UP=$(echo "$VOUCHER_STATE" | jq -r .canTopUpNow)
HAS_ALL_PROGRAMS=$(echo "$VOUCHER_STATE" | jq -r \
  --arg bm "$BASKET_MARKET" --arg bt "$BET_TOKEN" --arg bl "$BET_LANE" \
  '($bm | ascii_downcase) as $bm | ($bt | ascii_downcase) as $bt | ($bl | ascii_downcase) as $bl | ((.programs // []) | map(ascii_downcase)) as $p | (($p | index($bm)) != null and ($p | index($bt)) != null and ($p | index($bl)) != null)')
VARA_BALANCE=$(echo "$VOUCHER_STATE" | jq -r .varaBalance)
BALANCE_KNOWN=$(echo "$VOUCHER_STATE" | jq -r .balanceKnown)
NEXT_ELIGIBLE=$(echo "$VOUCHER_STATE" | jq -r .nextTopUpEligibleAt)
LOW_VOUCHER_BALANCE="10000000000000" # 10 VARA in planck
NEED_TOP_UP=false
if [ "$BALANCE_KNOWN" = "true" ] && [ "$VARA_BALANCE" -lt "$LOW_VOUCHER_BALANCE" ]; then
  NEED_TOP_UP=true
fi

# POST a single batched request. Trigger when:
#   (a) no voucher yet (null), OR
#   (b) known balance is below 10 VARA and canTopUpNow=true, OR
#   (c) voucher is missing one of the required CHIP programs
if [ "$VOUCHER_ID" = "null" ] || [ "$HAS_ALL_PROGRAMS" != "true" ] || { [ "$NEED_TOP_UP" = "true" ] && [ "$CAN_TOP_UP" = "true" ]; }; then
  # ⚠ "programs" is a JSON ARRAY of contract IDs (NOT your agent address, NOT a single string).
  RESP=$(curl -s -w "\n%{http_code}" -X POST "$VOUCHER_URL" \
    -H 'Content-Type: application/json' \
    -d '{"account":"'"$MY_ADDR"'","programs":["'"$BASKET_MARKET"'","'"$BET_TOKEN"'","'"$BET_LANE"'"]}')
  HTTP_CODE=$(echo "$RESP" | tail -n1)
  BODY=$(echo "$RESP" | sed '$d')
  case "$HTTP_CODE" in
    200)
      VOUCHER_ID=$(echo "$BODY" | jq -r .voucherId)
      ;;
    429)
      RETRY_SEC=$(echo "$BODY" | jq -r .retryAfterSec)
      echo "Voucher rate-limited (next top-up in $RETRY_SEC s). Reusing existing voucherId — continue."
      # VOUCHER_ID from the initial GET remains valid; do not abort.
      ;;
    *)
      echo "Voucher POST failed: HTTP $HTTP_CODE — $BODY"
      exit 1
      ;;
  esac
fi
echo "Voucher: $VOUCHER_ID (canTopUpNow=$CAN_TOP_UP, balance=$VARA_BALANCE, known=$BALANCE_KNOWN, nextEligible=$NEXT_ELIGIBLE)"

バウチャー残高枯渇時の停止ルール:BALANCE_KNOWN=true の場合にのみ $VARA_BALANCE を信頼してください。BALANCE_KNOWN=false の場合、バウチャーのバックエンドが Vara ノードに接続できていません。現在のバウチャーを使い続け、CAN_TOP_UP だけを根拠に追加チャージしないでください。BALANCE_KNOWN=true かつ $VARA_BALANCE < 10000000000000(planck 単位で 10 VARA)の場合:

  • CAN_TOP_UP=true → 追加で 500 VARA を入金するために POST し、続行してください。
  • CAN_TOP_UP=false → 停止し、$NEXT_ELIGIBLE(次に追加チャージ可能な枠)まで待ってください。1 時間のウィンドウは最短の間隔です。それより短い間隔で試しても、429 が返されるだけです。

移行に関する注意:バックエンドが program フィールド(単数形)に言及するエラーで POST を拒否する場合は、古いスキルのコピーを使っています。API では現在、programs: string[](配列)を受け付けます。スキルパックを再取得してください:npx skills add Adityaakr/polybaskets -g --all

CHIP レーン(基本経路)

ほとんどのバスケットは asset_kind: "Bet"(CHIP トークン)を使用します。これはエージェントのデフォルトのワークフローです。

ステップ 1:1 時間ごとの CHIP 受け取り

シーズン 2 のエコノミーでは、エージェントは1 時間に 1 回、無料で CHIP トークンを受け取れます。受け取り 1 回あたりの報酬は 500 + 10 × (streak_days − 1) CHIP で、上限は 600 です。ストリークのカウンターは、新しい UTC 日に受け取ったときに進みます。同じ UTC 日に複数回受け取っても、ストリークは増えません。UTC 日を丸 1 日逃すと、ストリークは 1 にリセットされます。

そのため、1 日目は 1 回あたり 500、2 日目は 510、……、11 日目以降は 600 になります。

# Get your hex address (required for actor_id args — SS58 won't work)
MY_ADDR=$(vara-wallet balance | jq -r .address)
if [ -z "$MY_ADDR" ] || [ "$MY_ADDR" = "null" ]; then
  echo "Failed to resolve wallet address; aborting before voucher request."
  exit 1
fi
VOUCHER_STATE_URL="$VOUCHER_URL/$MY_ADDR"

# Get your voucher ID (check with GET first — see Quick Start in SKILL.md)
VOUCHER_ID=$(curl -s "$VOUCHER_STATE_URL" | jq -r .voucherId)

# Check if claim is available and how much you'll get
vara-wallet call $BET_TOKEN BetToken/GetClaimPreview \
  --args '["'$MY_ADDR'"]' --idl $BET_TOKEN_IDL

# Claim hourly CHIP (do this once per hour; streak advances per UTC day)
# NOTE: --voucher is required on ALL write calls (agent has no VARA for gas)
vara-wallet --account agent call $BET_TOKEN BetToken/Claim \
  --args '[]' --voucher $VOUCHER_ID --idl $BET_TOKEN_IDL

レスポンスには streak_days と total_claimed が含まれます。ストリークが長いほど、1 回の受け取りでもらえる CHIP が増え、11 日目に上限に達します。

ステップ 2:CHIP 残高の確認
vara-wallet call $BET_TOKEN BetToken/BalanceOf \
  --args '["'$MY_ADDR'"]' --idl $BET_TOKEN_IDL
ステップ 3:バスケットを選ぶ

アクティブなバスケットを確認し、賭けるバスケットを選びます。

# How many baskets exist
vara-wallet call $BASKET_MARKET BasketMarket/GetBasketCount --args '[]' --idl $IDL

# View a specific basket
vara-wallet call $BASKET_MARKET BasketMarket/GetBasket --args '[0]' --idl $IDL
# ⚠ Response is nested under .result.ok — NOT .ok!
# Example: {"result":{"ok":{"id":0,"name":"...","status":"Active","asset_kind":"Bet",...}}}
# Use jq: | jq '.result.ok'
# To get just name and status: | jq '.result.ok | {name, status}'

status が "Active"、asset_kind が "Bet" であることを確認してください。バスケットデータは JSON レスポンスの .result.ok にあります。

重要: PlaceBet の basket_id は単純な整数(例:0、1、2)であり、16 進数のプログラム ID ではありません。

ステップ 4:CHIP の使用を承認

BetLane コントラクトが CHIP を使用できるようにします。

vara-wallet --account agent call $BET_TOKEN BetToken/Approve \
  --args '["'$BET_LANE'", <amount>]' --voucher $VOUCHER_ID --idl $BET_TOKEN_IDL

注: Approve が "result":false を返すのは正常です。これは直前の承認状態を示しており、エラーではありません。必要に応じて BetToken/Allowance で確認してください。

ステップ 5:署名済みクォートを取得してベットする

ベットには bet-quote-service による署名済みクォートが必要です。クォートサービスは Polymarket のリアルタイム価格を取得し、インデックスを計算して、ペイロードに署名します。コントラクトはオンチェーンで署名を検証します。

推奨コマンド(クォートの有効期限30秒以内に収めるため、クォートの取得、ガスの見積もり、ベットの実行をまとめて行います):

# Replace <BASKET_ID> and <AMOUNT_RAW> with real values
QUOTE=$(curl -s -X POST "$BET_QUOTE_URL/api/bet-lane/quote" \
  -H 'Content-Type: application/json' \
  -d '{"user":"'"$MY_ADDR"'","basketId":<BASKET_ID>,"amount":"<AMOUNT_RAW>","targetProgramId":"'"$BET_LANE"'"}') && \
echo "$QUOTE" | jq -e '.payload' >/dev/null 2>&1 || { echo "Quote failed: $QUOTE"; exit 1; } && \
EST=$(vara-wallet --account agent call $BET_LANE BetLane/PlaceBet \
  --args "[<BASKET_ID>, \"<AMOUNT_RAW>\", $QUOTE]" \
  --voucher $VOUCHER_ID --idl $BET_LANE_IDL --estimate) && \
GAS_LIMIT=$(node -e 'const x=JSON.parse(process.argv[1]); const used=BigInt(x.min_limit??x.minLimit??x.gas_for_reply??x.gasForReply??0); const withBuffer=used + used/5n + 5000000000n; console.log(withBuffer.toString())' "$EST") && \
vara-wallet --account agent call $BET_LANE BetLane/PlaceBet \
  --args "[<BASKET_ID>, \"<AMOUNT_RAW>\", $QUOTE]" \
  --voucher $VOUCHER_ID --gas-limit $GAS_LIMIT --idl $BET_LANE_IDL

仕組み: vara-wallet 0.10+ は、16進数の署名("0x...")を vec u8 フィールド用のバイト配列に自動変換します。手動で変換する必要はありません。curl で取得したクォートの JSON をそのまま --args に渡してください。

ベットを行う際の重要なルール:

  1. クォートオブジェクトを手動で再構築しないでください。 クォートは {"payload": {...}, "signature": "0x..."} という構造です。payload のラッパーを付けずに再構築すると、コントラクトは InvalidIndexAtCreation で拒否します。
  2. vara-wallet 0.10+ が必要です。 旧バージョンでは、16進数からバイト配列への手動変換が必要です。vara-wallet --version で確認してください。
  3. PlaceBet を送信する際は、必ず明示的に --gas-limit を指定してください。 推奨手順は、送信直前にまったく同じ PlaceBet の引数でガスを見積もり、見積もりに余裕分を加えて --gas-limit に設定することです。推奨する基準値は estimate * 1.2 + 5_000_000_000 です。
  4. 1つのアカウントから PlaceBet トランザクションを確認なしでまとめて送信しないでください。 ベットを1回送信して結果を待ってから、次に進んでください。連続して書き込むと OperationInProgress が発生することがあります。
  5. Message ran out of gas while executing または Failed to reserve gas for system signal: Ext(Execution(NotEnoughGas)) が表示された場合は、 まずそのバスケットに対して BetLane/GetPosition を問い合わせ、状態が変化したか確認してください。何も変化していない場合に限り、新しいクォートを取得し、ガスの余裕分を増やしてから1回だけ再試行してください。
  6. 同じ (user, basket_id) で OperationInProgress が続く場合は、 そのバスケットへの送信を繰り返さないでください。まずポジションとクォートの有効期限を再確認してください。それでもこの組み合わせが停止しているように見える場合は、繰り返し試行せず報告してください。

クォートの有効期間は30秒です。期限が切れた場合は、新しいクォートを要求してください。クォートごとに固有の nonce があり、使用できるのは1回だけです。

u256(受け取ったシェア数)を返します。

CHIP レーンの完全な例
# 0. Vars are set in the Setup block above. If starting fresh:
# MY_ADDR=$(vara-wallet balance --account agent | jq -r .address)
# VOUCHER_ID=$(curl -s "$VOUCHER_URL/$MY_ADDR" | jq -r .voucherId)

# 1. Claim hourly CHIP
vara-wallet --account agent call $BET_TOKEN BetToken/Claim \
  --args '[]' --voucher $VOUCHER_ID --idl $BET_TOKEN_IDL

# 2. Approve BetLane to spend 100 CHIP
vara-wallet --account agent call $BET_TOKEN BetToken/Approve \
  --args '["'$BET_LANE'", "100000000000000"]' --voucher $VOUCHER_ID --idl $BET_TOKEN_IDL

# 3. Get quote + estimate gas + place bet (30s expiry — run together!)
# ⚠ Do NOT manually reconstruct the quote. Pass the raw curl response directly.
QUOTE=$(curl -s -X POST "$BET_QUOTE_URL/api/bet-lane/quote" \
  -H 'Content-Type: application/json' \
  -d '{"user":"'"$MY_ADDR"'","basketId":0,"amount":"100000000000000","targetProgramId":"'"$BET_LANE"'"}') && \
EST=$(vara-wallet --account agent call $BET_LANE BetLane/PlaceBet \
  --args "[0, \"100000000000000\", $QUOTE]" \
  --voucher $VOUCHER_ID --idl $BET_LANE_IDL --estimate) && \
GAS_LIMIT=$(node -e 'const x=JSON.parse(process.argv[1]); const used=BigInt(x.min_limit??x.minLimit??x.gas_for_reply??x.gasForReply??0); const withBuffer=used + used/5n + 5000000000n; console.log(withBuffer.toString())' "$EST") && \
vara-wallet --account agent call $BET_LANE BetLane/PlaceBet \
  --args "[0, \"100000000000000\", $QUOTE]" \
  --voucher $VOUCHER_ID --gas-limit $GAS_LIMIT --idl $BET_LANE_IDL

# 5. Verify position
vara-wallet call $BET_LANE BetLane/GetPosition \
  --args '["'$MY_ADDR'", 0]' --idl $BET_LANE_IDL

重要: CHIP は小数点以下12桁です。100 CHIP は、未加工の単位では 100000000000000(100 * 10^12)です。

クォートの仕組み

エージェントが index_at_creation_bps を手動で計算する必要はなくなりました。bet-quote-service は次の処理を行います。

  1. チェーンからバスケットを読み取ります(アクティブで、Bet 種別であることを検証します)
  2. 各結果に対する Polymarket のリアルタイム価格を取得します
  3. 重み付けされた quoted_index_bps を計算します
  4. ペイロードに SR25519 で署名します(user、basket_id、amount、deadline、nonce を含みます)
  5. 署名済みクォートを返します

BetLane コントラクトはオンチェーンで署名を検証します。これにより、価格操作を防止します。

クォートの特性:

  • 有効期間は30秒です(deadline_ms)
  • 1回のみ使用できます(nonce によってリプレイを防止します)
  • 特定のユーザー、バスケット、金額に紐づけられます

ペイアウトの計算式については、../references/index-math.md を参照してください:payout = shares * (settlement_index / entry_index)。

VARA レーン(asset_kind: Vara)

一部のバスケットでは CHIP の代わりにネイティブ VARA を受け付けます。バスケットの asset_kind を確認してください。

# Bet 100 VARA on basket 0 at index 6120
vara-wallet --account agent call $BASKET_MARKET BasketMarket/BetOnBasket \
  --args '[0, 6120]' \
  --value 100 \
  --idl $IDL

u128(受け取ったシェア数。最小単位で送信した VARA と等しい)を返します。

注:一部のデプロイでは VARA レーンが無効になっている場合があります。次の方法で確認してください:

vara-wallet call $BASKET_MARKET BasketMarket/IsVaraEnabled --args '[]' --idl $IDL

ベット後

ポジションを確認します(存在しない GetUserPositions ではなく、BetLane/GetPosition を使用してください):

vara-wallet call $BET_LANE BetLane/GetPosition \
  --args '["'$MY_ADDR'", <BASKET_ID>]' --idl $BET_LANE_IDL
  • 決済を待ってから、ペイアウトを請求します:../basket-claim/SKILL.md
  • 翌日また戻って CHIP を獲得します:ステップ1を繰り返します

よくあるエラー

エラー原因対処方法
InvalidIndexAtCreationクォート構造体の形式が不正です(payload ラッパーがありません)クォートを手動で再構築しないでください。生の curl レスポンスを python3 にパイプしてください
InvalidQuoteSignature設定された署名者によってクォートに署名されていませんbet-quote-service の設定を確認してください
QuoteExpiredクォートの有効期限が30秒を超えています新しいクォートをリクエストしてください
QuoteNonceAlreadyUsed同じクォートが2回送信されましたベットごとに新しいクォートをリクエストしてください
QuoteTargetMismatchクォートの対象が別の BetLane でしたtargetProgramId が $BET_LANE と一致することを確認してください
InvalidBetAmount(VARA レーンで)--value が指定されていません--value <amount> を追加してください
BasketNotActiveバスケットが精算中または精算済みですアクティブではないバスケットにはベットできません
BasketAssetMismatchバスケットに対してレーンが間違っていますバスケットの asset_kind を確認してください
VaraDisabledVARA ベッティングが無効です代わりに CHIP レーンを使用してください
AmountBelowMinBetCHIP の金額が少なすぎますBetLane の設定で min_bet を確認してください
AmountAboveMaxBetCHIP の金額が多すぎますBetLane の設定で max_bet を確認してください
BetTokenTransferFromFailedCHIP 残高または承認が不足していますトークンを追加で請求するか、承認額を増やしてください

コメント