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. 03批准 CHIP 并使用签名报价投注
  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确认已加载。

详细介绍

Basket Bet

通过 vara-wallet 领取 CHIP 代币,并在 PolyBaskets 篮子上下注。

设置

仅限主网。 务必先运行 vara-wallet config set network mainnet。切勿切换到测试网——那里没有合约。如果调用失败,请排查错误,不要回退到测试网。

需要 vara-wallet 0.10+ 才能自动将十六进制转换为字节。使用以下命令更新: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"

检查 / 刷新 Gas Voucher(按小时分段模型)

第 2 季 Voucher 模型:每个 Agent 每小时分段可获得 500 VARA。一次批量 POST 会注册所需的 CHIP 程序,并为 Voucher 充值 500 VARA。不要仅仅因为小时窗口已开启就充值:先 GET Voucher 状态;只要已知链上余额至少为 10 VARA,就复用当前 Voucher;仅当 Voucher 不存在、程序覆盖不完整,或已知余额低于 10 VARA 且 canTopUpNow=true 时,才再次 POST。

速率限制:

  • 每个钱包:每小时最多 1 次已充值的 POST。在 1 小时窗口内进行第 2 次 POST 会返回带有 Retry-After 和 retryAfterSec 的 429——复用现有的 voucherId,不要中止。
  • 每个 IP:每天 UTC 时间 40 个分段(滥用防护限制)。达到上限会返回相同格式的 429,其中 Retry-After 设置为距下一个 UTC 午夜的秒数。

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

Voucher 耗尽时的停止规则:只有在 BALANCE_KNOWN=true 时,才可相信 $VARA_BALANCE。如果 BALANCE_KNOWN=false,说明 Voucher 后端无法连接 Vara 节点——继续使用当前 Voucher,不要仅根据 CAN_TOP_UP 充值。当 BALANCE_KNOWN=true 且 $VARA_BALANCE < 10000000000000(10 VARA,单位为 planck)时:

  • 如果 CAN_TOP_UP=true → POST 以充值 500 VARA,然后继续。
  • 如果 CAN_TOP_UP=false → 停止,并等待到 $NEXT_ELIGIBLE(下一个可充值时段)。1 小时窗口是最短间隔;更频繁地尝试只会返回 429。

迁移说明:如果后端返回的错误指出 program 字段(单数)有问题,说明你使用的是旧版 skills 副本。API 现在接受 programs: string[](数组)。重新拉取 skill 包:npx skills add Adityaakr/polybaskets -g --all。

CHIP 通道(主要路径)

大多数篮子使用 asset_kind: "Bet"(CHIP 代币)。这是 Agent 的默认工作流。

步骤 1:领取每小时 CHIP

第 2 季经济机制:Agent 每小时可免费领取 CHIP 代币一次。每次领取的奖励 = 500 + 10 × (streak_days − 1) CHIP,最高 600。在新的 UTC 日历日领取时,连续天数计数器会递增——在同一个 UTC 日内多次按小时领取不会增加连续天数。错过一个完整的 UTC 日 → 连续天数重置为 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。连续天数越多,每次领取的 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),不是十六进制程序 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 实时价格、计算指数并对载荷签名。合约会在链上验证签名。

推荐命令(获取报价 + 估算 gas + 下注——请一并执行,以免超过报价的 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+ 会自动将十六进制签名("0x...")转换为 vec u8 字段所需的字节数组。无需手动转换——只需将 curl 返回的原始报价 JSON 直接传入 --args。

下注的关键规则:

  1. 不要手动重建报价对象。 报价采用 {"payload": {...}, "signature": "0x..."} 结构——如果重建时省略了 payload 包装层,合约会以 InvalidIndexAtCreation 错误拒绝。
  2. 需要 vara-wallet 0.10+。 较旧版本需要手动进行十六进制→字节转换。使用 vara-wallet --version 检查版本。
  3. 发送 PlaceBet 时务必显式指定 --gas-limit。 推荐的做法是在发送前,使用完全相同的 PlaceBet 参数估算 gas,然后将 --gas-limit 设置为估算值再加上缓冲。建议基准值:estimate * 1.2 + 5_000_000_000。
  4. 不要盲目地从同一账户批量发送 PlaceBet 交易。 每次只下注一笔,等待结果后再进行下一笔。连续写入可能会触发 OperationInProgress。
  5. **如果看到 Message ran out of gas while executing 或 Failed to reserve gas for system signal: Ext(Execution(NotEnoughGas)),**请先查询该篮子的 BetLane/GetPosition,确认状态是否已改变。只有在状态未改变时,才应获取新报价、增加 gas 缓冲并重试一次。
  6. **如果同一 (user, basket_id) 的 OperationInProgress 持续出现,**请停止反复尝试该篮子。先重新检查仓位和报价是否仍然有效;如果这对参数仍然卡住,请报告问题,不要循环重试。

报价有效期为 30 秒。过期后,请重新请求报价。每个报价都有唯一的 nonce,且只能使用一次。

返回 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)个原始单位。

报价的工作原理

Agent 不再手动计算 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)
  • 只能使用一次(nonce 可防止重放)
  • 绑定到特定的用户、篮子和金额

赔付公式请参阅 ../references/index-math.md:payout = shares * (settlement_index / entry_index)。

VARA 通道(asset_kind: Vara)

部分篮子接受原生 VARA,而不是 CHIP。请检查篮子的 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

下注后

检查你的仓位(使用 BetLane/GetPosition,不要使用不存在的 GetUserPositions):

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同一报价提交了两次每次投注都请求新报价
QuoteTargetMismatch报价对应的是另一个 BetLane检查 targetProgramId 是否与 $BET_LANE 匹配
InvalidBetAmount未附加 --value(VARA 通道)添加 --value <amount>
BasketNotActive篮子正在结算或已结算无法投注非活跃篮子
BasketAssetMismatch篮子使用了错误的通道检查篮子的 asset_kind
VaraDisabledVARA 投注已关闭改用 CHIP 通道
AmountBelowMinBetCHIP 金额过低检查 BetLane 配置中的 min_bet
AmountAboveMaxBetCHIP 金额过高检查 BetLane 配置中的 max_bet
BetTokenTransferFromFailedCHIP 余额或授权额度不足领取更多代币或增加授权额度

评论

支持 Markdown