{
  "schemaVersion": "1.0",
  "item": {
    "slug": "torchpredictionmarketkit",
    "name": "Torch Prediction Market Kit",
    "source": "tencent",
    "type": "skill",
    "category": "AI 智能",
    "sourceUrl": "https://clawhub.ai/mrsirg97-rgb/torchpredictionmarketkit",
    "canonicalUrl": "https://clawhub.ai/mrsirg97-rgb/torchpredictionmarketkit",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/torchpredictionmarketkit",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=torchpredictionmarketkit",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "agent.json",
      "audit.md",
      "verification.md",
      "SKILL.md",
      "design.md",
      "whitepaper.md"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/torchpredictionmarketkit"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/torchpredictionmarketkit",
    "agentPageUrl": "https://openagent3.xyz/skills/torchpredictionmarketkit/agent",
    "manifestUrl": "https://openagent3.xyz/skills/torchpredictionmarketkit/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/torchpredictionmarketkit/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Torch Prediction Market Kit",
        "body": "You're here because you want to run prediction markets on Torch Market -- and you want to do it safely.\n\nEvery prediction market is a Torch token. The bonding curve is the AMM -- no LP setup, deterministic pricing, instant liquidity. The 10% treasury accumulates fees from every buy. Users buy the token to bet YES (price goes up), sell to bet NO (price goes down). At the deadline, the oracle checks the outcome and the bot records it.\n\nSettlement model: token-as-signal. No payout mechanism. The token price IS the prediction. The bonding curve and treasury do the work.\n\nThat's where this bot comes in.\n\nIt reads your markets.json file, creates Torch tokens for pending markets, seeds them with initial liquidity from your vault, monitors price and volume, and resolves them at the deadline using an oracle (CoinGecko price feed or manual). All value routes through your vault. The agent wallet that signs transactions holds nothing.\n\nThis is not a read-only scanner. This is a fully operational market maker that generates its own keypair, verifies vault linkage, creates tokens, seeds liquidity, and resolves markets autonomously in a continuous loop."
      },
      {
        "title": "How It Works",
        "body": "┌─────────────────────────────────────────────────────────┐\n│                   MARKET CYCLE LOOP                       │\n│                                                          │\n│  1. Load market definitions from markets.json            │\n│  2. For each pending market:                             │\n│     → buildCreateTokenTransaction(name, symbol, uri)     │\n│     → sign + submit + confirm                            │\n│     → buildBuyTransaction(vault, mint, seed SOL)         │\n│     → sign + submit + confirm                            │\n│     → update status to 'active', save mint address       │\n│  3. For each active market:                              │\n│     → getToken(mint) — snapshot price, volume, holders   │\n│     → if deadline passed:                                │\n│        → checkOracle(oracle) — price feed or manual      │\n│        → update status to 'resolved', record outcome     │\n│  4. Save updated markets.json                            │\n│  5. Sleep SCAN_INTERVAL_MS, repeat                       │\n│                                                          │\n│  All SOL comes from vault. Agent wallet holds nothing.   │\n│  Vault is the boundary.                                  │\n└─────────────────────────────────────────────────────────┘"
      },
      {
        "title": "The Agent Keypair",
        "body": "The bot generates a fresh Keypair in-process on every startup. No private key file. No environment variable (unless you want to provide one). The keypair is disposable -- it signs transactions but holds nothing of value.\n\nOn first run, the bot checks if this keypair is linked to your vault. If not, it prints the exact SDK call you need to link it:\n\n--- ACTION REQUIRED ---\nagent wallet is NOT linked to the vault.\nlink it by running (from your authority wallet):\n\n  buildLinkWalletTransaction(connection, {\n    authority: \"<your-authority-pubkey>\",\n    vault_creator: \"<your-vault-creator>\",\n    wallet_to_link: \"<agent-pubkey>\"\n  })\n\nthen restart the bot.\n-----------------------\n\nLink it from your authority wallet (hardware wallet, multisig, whatever you use). The agent never needs the authority's key. The authority never needs the agent's key. They share a vault, not keys."
      },
      {
        "title": "The Vault",
        "body": "This is the same Torch Vault from the full Torch Market protocol. It holds all assets -- SOL and tokens. The agent is a disposable controller.\n\nWhen the bot creates and seeds a market:\n\nToken creation — agent signs as creator, no SOL cost beyond gas\nSeed liquidity — SOL comes from the vault via buildBuyTransaction(vault=creator)\nTokens purchased — go to the vault's associated token account (ATA)\n\nThe human principal retains full control:\n\nwithdrawVault() — pull SOL at any time\nwithdrawTokens(mint) — pull market tokens at any time\nunlinkWallet(agent) — revoke agent access instantly\n\nIf the agent keypair is compromised, the attacker gets dust and vault access that you revoke in one transaction."
      },
      {
        "title": "1. Install",
        "body": "npm install torch-prediction-market-kit@2.0.2\n\nOr use the bundled source from ClawHub — the Torch SDK is included in lib/torchsdk/ and the bot source is in lib/kit/."
      },
      {
        "title": "2. Create and Fund a Vault (Human Principal)",
        "body": "From your authority wallet:\n\nimport { Connection } from \"@solana/web3.js\";\nimport {\n  buildCreateVaultTransaction,\n  buildDepositVaultTransaction,\n} from \"./lib/torchsdk/index.js\";\n\nconst connection = new Connection(process.env.SOLANA_RPC_URL);\n\n// Create vault\nconst { transaction: createTx } = await buildCreateVaultTransaction(connection, {\n  creator: authorityPubkey,\n});\n// sign and submit with authority wallet...\n\n// Fund vault with SOL for market creation + seed liquidity\nconst { transaction: depositTx } = await buildDepositVaultTransaction(connection, {\n  depositor: authorityPubkey,\n  vault_creator: authorityPubkey,\n  amount_sol: 5_000_000_000, // 5 SOL\n});\n// sign and submit with authority wallet..."
      },
      {
        "title": "3. Define Markets",
        "body": "Create markets.json:\n\n[\n  {\n    \"id\": \"sol-200-mar\",\n    \"question\": \"Will SOL be above $200 by March 1, 2026?\",\n    \"symbol\": \"SOL200M\",\n    \"name\": \"SOL Above 200 March\",\n    \"oracle\": {\n      \"type\": \"price_feed\",\n      \"asset\": \"solana\",\n      \"condition\": \"above\",\n      \"target\": 200\n    },\n    \"deadline\": 1740787200,\n    \"initialLiquidityLamports\": 100000000,\n    \"metadataUri\": \"https://arweave.net/placeholder\"\n  }\n]"
      },
      {
        "title": "4. Run the Bot",
        "body": "VAULT_CREATOR=<your-vault-creator-pubkey> SOLANA_RPC_URL=<rpc-url> npx torch-prediction-market-bot\n\nOn first run, the bot prints the agent keypair and instructions to link it. Link it from your authority wallet, then restart."
      },
      {
        "title": "5. Configuration",
        "body": "VariableRequiredDefaultDescriptionSOLANA_RPC_URLYes--Solana RPC endpoint (HTTPS). Fallback: RPC_URLVAULT_CREATORYes--Vault creator pubkeySOLANA_PRIVATE_KEYNo--Disposable controller keypair (base58 or JSON byte array). If omitted, generates fresh keypair on startup (recommended)SCAN_INTERVAL_MSNo60000Milliseconds between market cycles (min 5000)LOG_LEVELNoinfodebug, info, warn, errorMARKETS_PATHNo./markets.jsonPath to market definitions file"
      },
      {
        "title": "Architecture",
        "body": "packages/kit/src/\n├── index.ts      — entry point: keypair generation, vault verification, market cycle loop\n├── config.ts     — loadConfig(): validates SOLANA_RPC_URL, VAULT_CREATOR, MARKETS_PATH, etc.\n├── types.ts      — Market, Oracle, MarketSnapshot, BotConfig interfaces\n├── markets.ts    — loadMarkets(), saveMarkets(), createMarket(), snapshotMarket(), resolveMarket()\n├── oracle.ts     — checkPriceFeed(), checkOracle() — CoinGecko price resolution\n└── utils.ts      — sol(), createLogger(), decodeBase58(), withTimeout()\n\nThe bot is ~280 lines of TypeScript across 6 modules. It does three things: create markets, monitor them, and resolve them through the vault."
      },
      {
        "title": "Dependencies",
        "body": "PackageVersionPurpose@solana/web3.js1.98.4Solana RPC, keypair, transactiontorchsdk3.7.23Token queries, token creation, buy builder, vault queries\n\nTwo runtime dependencies. Both pinned to exact versions. No ^ or ~ ranges."
      },
      {
        "title": "Market Lifecycle",
        "body": "pending ──→ active ──→ resolved\n              │\n              └──→ cancelled\n\nStatusDescriptionpendingMarket defined in markets.json, no token created yetactiveTorch token created on bonding curve, users can traderesolvedDeadline passed, oracle checked, outcome recorded (yes/no)cancelledMarket removed before resolution (manual edit)"
      },
      {
        "title": "Market Definition",
        "body": "interface MarketDefinition {\n  id: string                  // unique market identifier\n  question: string            // human-readable question\n  symbol: string              // token symbol (max 10 chars)\n  name: string                // token name (max 32 chars)\n  oracle: Oracle              // how the market resolves\n  deadline: number            // unix timestamp (seconds)\n  initialLiquidityLamports: number  // SOL to seed bonding curve (in lamports, max 10 SOL)\n  metadataUri: string         // token metadata URI (allowlisted domains only)\n}"
      },
      {
        "title": "Input Validation",
        "body": "All pending markets are validated on load. Markets with invalid inputs are rejected before any on-chain action.\n\nFieldConstraintRejected ExampleidMust be unique across all marketsDuplicate \"sol-200-mar\"metadataUriDomain must be in allowlist: arweave.net, gateway.irys.xyz, ipfs.io, cloudflare-ipfs.com, nftstorage.link, dweb.linkhttps://evil.com/payload.jsoninitialLiquidityLamportsMax 10 SOL (10,000,000,000 lamports), non-negative50000000000 (50 SOL)oracle.assetMust be in allowlist of known CoinGecko IDs (solana, bitcoin, ethereum, etc.)\"arbitrary-string\"\n\nThese constraints ensure a compromised markets.json cannot trigger arbitrary URI fetches, drain the vault, or make unintended API calls."
      },
      {
        "title": "Price Feed Oracle (CoinGecko)",
        "body": "The primary oracle. Fetches the current price of an asset and compares it against a target.\n\n{\n  \"type\": \"price_feed\",\n  \"asset\": \"solana\",\n  \"condition\": \"above\",\n  \"target\": 200\n}\n\nasset — CoinGecko asset ID (e.g. \"solana\", \"bitcoin\", \"ethereum\")\ncondition — \"above\" or \"below\"\ntarget — USD price threshold\nResolution: if condition is \"above\", outcome is \"yes\" when price > target, \"no\" otherwise"
      },
      {
        "title": "Manual Oracle",
        "body": "Fallback for markets that can't be resolved by a price feed.\n\n{\n  \"type\": \"manual\",\n  \"source\": \"Twitter announcement from @torch_market\"\n}\n\nResolution: edit markets.json directly — set \"status\": \"resolved\" and \"outcome\": \"yes\" or \"no\"."
      },
      {
        "title": "Vault Safety Model",
        "body": "The same seven guarantees from the Torch Market vault apply here:\n\nPropertyGuaranteeFull custodyVault holds all SOL and all market tokens. Agent wallet holds nothing.Closed loopSeed liquidity SOL comes from vault, purchased tokens go to vault ATA. No leakage to agent.Authority separationCreator (immutable PDA seed) vs Authority (transferable admin) vs Controller (disposable signer).One link per walletAgent can only belong to one vault. PDA uniqueness enforces this on-chain.Permissionless depositsAnyone can top up the vault. Hardware wallet deposits, agent creates markets.Instant revocationAuthority can unlink the agent at any time. One transaction.Authority-only withdrawalsOnly the vault authority can withdraw SOL or tokens. The agent cannot extract value."
      },
      {
        "title": "The Closed Economic Loop for Market Creation",
        "body": "DirectionFlowSOL outVault → Bonding curve (seed liquidity buy)Tokens inBonding curve → Vault ATA (purchased tokens)Treasury10% of each buy accumulates in token treasury\n\nThe vault's seed tokens remain on the bonding curve. Users trade against the curve. Treasury grows from fees. The authority can withdraw vault tokens or SOL at any time."
      },
      {
        "title": "SDK Functions Used",
        "body": "The bot uses a focused subset of the Torch SDK:\n\nFunctionPurposegetVault(connection, creator)Verify vault exists on startupgetVaultForWallet(connection, wallet)Verify agent is linked to vaultbuildCreateTokenTransaction(connection, params)Build token creation transaction for new marketbuildBuyTransaction(connection, params)Build vault-routed buy to seed initial liquiditygetToken(connection, mint)Get token price, volume, status for market snapshotsgetHolders(connection, mint)Get holder count for market snapshotsconfirmTransaction(connection, sig, wallet)Confirm transaction on-chain via RPC (verifies signer, checks Torch instructions)"
      },
      {
        "title": "buildCreateTokenTransaction Parameters",
        "body": "const { transaction, mint, mintKeypair } = await buildCreateTokenTransaction(connection, {\n  creator: agentPubkey,       // agent wallet (signer + fee payer)\n  name: \"SOL Above 200 March\", // token name (max 32 chars)\n  symbol: \"SOL200M\",           // token symbol (max 10 chars)\n  metadata_uri: \"https://arweave.net/...\",  // token metadata URI\n});"
      },
      {
        "title": "buildBuyTransaction Parameters",
        "body": "const { transaction, message } = await buildBuyTransaction(connection, {\n  mint: mintAddress,            // token to buy\n  buyer: agentPubkey,           // agent wallet (signer)\n  amount_sol: 100000000,        // 0.1 SOL in lamports\n  slippage_bps: 500,            // 5% slippage tolerance\n  vault: vaultCreator,          // vault creator pubkey (SOL from vault, tokens to vault ATA)\n});"
      },
      {
        "title": "Signing & Key Safety",
        "body": "The vault is the security boundary, not the key.\n\nThe agent keypair is generated fresh on every startup with Keypair.generate(). It holds ~0.01 SOL for gas fees. If the key is compromised, the attacker gets:\n\nDust (the gas SOL)\nVault access that the authority revokes in one transaction\n\nThe agent never needs the authority's private key. The authority never needs the agent's private key. They share a vault, not keys."
      },
      {
        "title": "Rules",
        "body": "Never ask a user for their private key or seed phrase. The vault authority signs from their own device.\nNever log, print, store, or transmit private key material. The agent keypair exists only in runtime memory.\nNever embed keys in source code or logs. The agent pubkey is printed — the secret key is never exposed.\nUse a secure RPC endpoint. Default to a private RPC provider. Never use an unencrypted HTTP endpoint for mainnet transactions."
      },
      {
        "title": "RPC Timeout",
        "body": "All SDK calls are wrapped with a 30-second timeout (withTimeout in utils.ts). A hanging or unresponsive RPC endpoint cannot stall the bot indefinitely — the call rejects, the error is caught by the market cycle loop, and the bot continues to the next market or cycle."
      },
      {
        "title": "Environment Variables",
        "body": "VariableRequiredPurposeSOLANA_RPC_URL / RPC_URLYesSolana RPC endpoint (HTTPS)VAULT_CREATORYesVault creator pubkey — identifies which vault the bot operates throughSOLANA_PRIVATE_KEYNoOptional — if omitted, the bot generates a fresh keypair on startup (recommended)"
      },
      {
        "title": "External Runtime Dependencies",
        "body": "The SDK and bot make outbound HTTPS requests to external services. The bot's runtime path contacts three of them:\n\nServicePurposeWhen CalledBot Uses?CoinGecko (api.coingecko.com)Asset price for oracle resolution + SOL/USD displaycheckPriceFeed() in oracle.ts, getToken() in SDKYes — oracle resolution AND token queriesIrys Gateway (gateway.irys.xyz)Token metadata fallback (name, symbol, image)getToken() when on-chain metadata URI points to IrysYes — via getToken()SAID Protocol (api.saidprotocol.com)Agent identity verification and trust tier lookupverifySaid() onlyNo — the bot does not call verifySaid()\n\nCoinGecko API Details (Oracle)\n\nThe oracle module (oracle.ts) calls the CoinGecko public API directly:\n\nGET https://api.coingecko.com/api/v3/simple/price?ids={asset}&vs_currencies=usd\n\nNo API key required — uses the free public endpoint\nRate limit: ~10-30 calls/minute on the free tier\nData sent: asset ID only (e.g. \"solana\") — no wallet, transaction, or agent data\nData received: { \"solana\": { \"usd\": 87.76 } }\nFailure mode: if CoinGecko is unreachable, checkPriceFeed() throws and the market stays unresolved until the next cycle\nCalled once per active market per cycle that has passed its deadline\n\nconfirmTransaction() does NOT contact SAID. Despite living in the SDK's said.js module, it only calls connection.getParsedTransaction() (Solana RPC) to verify the transaction succeeded on-chain and determine the event type. No data is sent to any external service.\n\nNo credentials are sent to CoinGecko or Irys. All requests are read-only GET. If either service is unreachable, the bot degrades gracefully. No private key material is ever transmitted to any external endpoint."
      },
      {
        "title": "Log Output",
        "body": "=== torch prediction market bot ===\nagent wallet: 7xK9...\nvault creator: 4yN2...\nmarkets file: ./markets.json\nscan interval: 60000ms\n\n[09:15:32] INFO  vault found — authority=8cpW...\n[09:15:32] INFO  agent wallet linked to vault — starting market cycle\n[09:15:32] INFO  treasury: 5.0000 SOL\n[09:15:33] INFO  CREATING | sol-200-mar — \"Will SOL be above $200 by March 1, 2026?\"\n[09:15:35] INFO  CREATED | sol-200-mar — mint=AqAgqKTypS... | seed=0.1000 SOL\n[09:16:35] DEBUG SNAPSHOT | sol-200-mar — price=0.000012 SOL | mcap=0.0120 | holders=3\n[09:17:35] INFO  RESOLVING | sol-200-mar — deadline reached\n[09:17:36] INFO  RESOLVED | sol-200-mar — outcome=no"
      },
      {
        "title": "Testing",
        "body": "Requires Surfpool running a mainnet fork:\n\nsurfpool start --network mainnet --no-tui\npnpm test\n\nTest result: 9 passed, 1 informational (Surfpool RPC limitation on getTokenLargestAccounts for Token-2022 — works on mainnet).\n\nTestWhat It ValidatesConnectionRPC reachableloadMarketsMarket file parsing and validationcheckPriceFeedCoinGecko oracle returns valid price databuildCreateTokenTransactionToken creation transaction builds correctlygetTokensDiscovers bonding/migrated tokensgetTokenToken metadata, price, statusgetHoldersHolder enumeration (skips on Surfpool limitation)getVaultForWalletVault link returns null for unlinked walletIn-process keypairNo external key required"
      },
      {
        "title": "Error Codes",
        "body": "VAULT_NOT_FOUND: No vault exists for this creator\nWALLET_NOT_LINKED: Agent wallet is not linked to the vault\nINVALID_MINT: Token not found\nBONDING_COMPLETE: Token has graduated — trade on DEX instead\nNAME_TOO_LONG: Token name exceeds 32 characters\nSYMBOL_TOO_LONG: Token symbol exceeds 10 characters"
      },
      {
        "title": "Links",
        "body": "Prediction Market Kit (source): github.com/mrsirg97-rgb/torch-prediction-market-kit\nPrediction Market Kit (npm): npmjs.com/package/torch-prediction-market-kit\nTorch SDK (bundled): lib/torchsdk/ -- included in this skill\nTorch SDK (source): github.com/mrsirg97-rgb/torchsdk\nTorch SDK (npm): npmjs.com/package/torchsdk\nTorch Market (protocol skill): clawhub.ai/mrsirg97-rgb/torchmarket\nWhitepaper: torch.market/whitepaper.md\nSecurity Audit: torch.market/audit.md\nWebsite: torch.market\nProgram ID: 8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT"
      },
      {
        "title": "v2.0.0",
        "body": "Upgraded torchsdk from 3.2.3 to 3.7.23. Major SDK update adds treasury lock PDAs (V27), dynamic Raydium network detection, auto-migration bundling on bonding curve completion (buildBuyTransaction now returns optional migrationTransaction), vault-routed Raydium CPMM swaps (buildVaultSwapTransaction), Token-2022 fee harvesting (buildHarvestFeesTransaction, buildSwapFeesToSolTransaction), bulk loan scanning (getAllLoanPositions), on-chain token metadata queries (getTokenMetadata), and ephemeral agent keypair factory (createEphemeralAgent).\nExported withTimeout utility. The timeout helper used internally by the bot is now a public export of the kit package, available to downstream consumers.\nUpdated env format in skill frontmatter. Environment variable declarations now use structured name/required format for compatibility with ClawHub and OpenClaw agent runners."
      },
      {
        "title": "v1.0.2",
        "body": "Updated kit to point to correct bundled sdk. The index.js file now imports the SDK from the local lib/torchsdk/ directory instead of the npm package. This ensures that the bot uses the exact bundled SDK version (3.2.3) included in the kit, rather than any potentially different version installed from npm. Addresses audit finding L-3."
      },
      {
        "title": "v1.0.1",
        "body": "Timeout on all external calls. Every SDK, RPC, and API call is now wrapped with a 30-second timeout (10 seconds for CoinGecko). If an RPC endpoint or CoinGecko becomes unresponsive, the call fails fast with a descriptive error instead of stalling the bot indefinitely. Addresses audit finding L-1.\nMarket ID uniqueness validation. loadMarkets() now rejects markets.json files containing duplicate market IDs on load, preventing unintended duplicate market creation and wasted vault SOL. Addresses audit finding L-2.\n\nThis bot exists because prediction markets need infrastructure. Torch bonding curves provide instant liquidity and deterministic pricing without LP setup. The vault makes it safe — all value stays in the escrow, all risk is bounded, and the human principal keeps the keys. The token price IS the prediction."
      }
    ],
    "body": "Torch Prediction Market Kit\n\nYou're here because you want to run prediction markets on Torch Market -- and you want to do it safely.\n\nEvery prediction market is a Torch token. The bonding curve is the AMM -- no LP setup, deterministic pricing, instant liquidity. The 10% treasury accumulates fees from every buy. Users buy the token to bet YES (price goes up), sell to bet NO (price goes down). At the deadline, the oracle checks the outcome and the bot records it.\n\nSettlement model: token-as-signal. No payout mechanism. The token price IS the prediction. The bonding curve and treasury do the work.\n\nThat's where this bot comes in.\n\nIt reads your markets.json file, creates Torch tokens for pending markets, seeds them with initial liquidity from your vault, monitors price and volume, and resolves them at the deadline using an oracle (CoinGecko price feed or manual). All value routes through your vault. The agent wallet that signs transactions holds nothing.\n\nThis is not a read-only scanner. This is a fully operational market maker that generates its own keypair, verifies vault linkage, creates tokens, seeds liquidity, and resolves markets autonomously in a continuous loop.\n\nHow It Works\n┌─────────────────────────────────────────────────────────┐\n│                   MARKET CYCLE LOOP                       │\n│                                                          │\n│  1. Load market definitions from markets.json            │\n│  2. For each pending market:                             │\n│     → buildCreateTokenTransaction(name, symbol, uri)     │\n│     → sign + submit + confirm                            │\n│     → buildBuyTransaction(vault, mint, seed SOL)         │\n│     → sign + submit + confirm                            │\n│     → update status to 'active', save mint address       │\n│  3. For each active market:                              │\n│     → getToken(mint) — snapshot price, volume, holders   │\n│     → if deadline passed:                                │\n│        → checkOracle(oracle) — price feed or manual      │\n│        → update status to 'resolved', record outcome     │\n│  4. Save updated markets.json                            │\n│  5. Sleep SCAN_INTERVAL_MS, repeat                       │\n│                                                          │\n│  All SOL comes from vault. Agent wallet holds nothing.   │\n│  Vault is the boundary.                                  │\n└─────────────────────────────────────────────────────────┘\n\nThe Agent Keypair\n\nThe bot generates a fresh Keypair in-process on every startup. No private key file. No environment variable (unless you want to provide one). The keypair is disposable -- it signs transactions but holds nothing of value.\n\nOn first run, the bot checks if this keypair is linked to your vault. If not, it prints the exact SDK call you need to link it:\n\n--- ACTION REQUIRED ---\nagent wallet is NOT linked to the vault.\nlink it by running (from your authority wallet):\n\n  buildLinkWalletTransaction(connection, {\n    authority: \"<your-authority-pubkey>\",\n    vault_creator: \"<your-vault-creator>\",\n    wallet_to_link: \"<agent-pubkey>\"\n  })\n\nthen restart the bot.\n-----------------------\n\n\nLink it from your authority wallet (hardware wallet, multisig, whatever you use). The agent never needs the authority's key. The authority never needs the agent's key. They share a vault, not keys.\n\nThe Vault\n\nThis is the same Torch Vault from the full Torch Market protocol. It holds all assets -- SOL and tokens. The agent is a disposable controller.\n\nWhen the bot creates and seeds a market:\n\nToken creation — agent signs as creator, no SOL cost beyond gas\nSeed liquidity — SOL comes from the vault via buildBuyTransaction(vault=creator)\nTokens purchased — go to the vault's associated token account (ATA)\n\nThe human principal retains full control:\n\nwithdrawVault() — pull SOL at any time\nwithdrawTokens(mint) — pull market tokens at any time\nunlinkWallet(agent) — revoke agent access instantly\n\nIf the agent keypair is compromised, the attacker gets dust and vault access that you revoke in one transaction.\n\nGetting Started\n1. Install\nnpm install torch-prediction-market-kit@2.0.2\n\n\nOr use the bundled source from ClawHub — the Torch SDK is included in lib/torchsdk/ and the bot source is in lib/kit/.\n\n2. Create and Fund a Vault (Human Principal)\n\nFrom your authority wallet:\n\nimport { Connection } from \"@solana/web3.js\";\nimport {\n  buildCreateVaultTransaction,\n  buildDepositVaultTransaction,\n} from \"./lib/torchsdk/index.js\";\n\nconst connection = new Connection(process.env.SOLANA_RPC_URL);\n\n// Create vault\nconst { transaction: createTx } = await buildCreateVaultTransaction(connection, {\n  creator: authorityPubkey,\n});\n// sign and submit with authority wallet...\n\n// Fund vault with SOL for market creation + seed liquidity\nconst { transaction: depositTx } = await buildDepositVaultTransaction(connection, {\n  depositor: authorityPubkey,\n  vault_creator: authorityPubkey,\n  amount_sol: 5_000_000_000, // 5 SOL\n});\n// sign and submit with authority wallet...\n\n3. Define Markets\n\nCreate markets.json:\n\n[\n  {\n    \"id\": \"sol-200-mar\",\n    \"question\": \"Will SOL be above $200 by March 1, 2026?\",\n    \"symbol\": \"SOL200M\",\n    \"name\": \"SOL Above 200 March\",\n    \"oracle\": {\n      \"type\": \"price_feed\",\n      \"asset\": \"solana\",\n      \"condition\": \"above\",\n      \"target\": 200\n    },\n    \"deadline\": 1740787200,\n    \"initialLiquidityLamports\": 100000000,\n    \"metadataUri\": \"https://arweave.net/placeholder\"\n  }\n]\n\n4. Run the Bot\nVAULT_CREATOR=<your-vault-creator-pubkey> SOLANA_RPC_URL=<rpc-url> npx torch-prediction-market-bot\n\n\nOn first run, the bot prints the agent keypair and instructions to link it. Link it from your authority wallet, then restart.\n\n5. Configuration\nVariable\tRequired\tDefault\tDescription\nSOLANA_RPC_URL\tYes\t--\tSolana RPC endpoint (HTTPS). Fallback: RPC_URL\nVAULT_CREATOR\tYes\t--\tVault creator pubkey\nSOLANA_PRIVATE_KEY\tNo\t--\tDisposable controller keypair (base58 or JSON byte array). If omitted, generates fresh keypair on startup (recommended)\nSCAN_INTERVAL_MS\tNo\t60000\tMilliseconds between market cycles (min 5000)\nLOG_LEVEL\tNo\tinfo\tdebug, info, warn, error\nMARKETS_PATH\tNo\t./markets.json\tPath to market definitions file\nArchitecture\npackages/kit/src/\n├── index.ts      — entry point: keypair generation, vault verification, market cycle loop\n├── config.ts     — loadConfig(): validates SOLANA_RPC_URL, VAULT_CREATOR, MARKETS_PATH, etc.\n├── types.ts      — Market, Oracle, MarketSnapshot, BotConfig interfaces\n├── markets.ts    — loadMarkets(), saveMarkets(), createMarket(), snapshotMarket(), resolveMarket()\n├── oracle.ts     — checkPriceFeed(), checkOracle() — CoinGecko price resolution\n└── utils.ts      — sol(), createLogger(), decodeBase58(), withTimeout()\n\n\nThe bot is ~280 lines of TypeScript across 6 modules. It does three things: create markets, monitor them, and resolve them through the vault.\n\nDependencies\nPackage\tVersion\tPurpose\n@solana/web3.js\t1.98.4\tSolana RPC, keypair, transaction\ntorchsdk\t3.7.23\tToken queries, token creation, buy builder, vault queries\n\nTwo runtime dependencies. Both pinned to exact versions. No ^ or ~ ranges.\n\nMarket Lifecycle\npending ──→ active ──→ resolved\n              │\n              └──→ cancelled\n\nStatus\tDescription\npending\tMarket defined in markets.json, no token created yet\nactive\tTorch token created on bonding curve, users can trade\nresolved\tDeadline passed, oracle checked, outcome recorded (yes/no)\ncancelled\tMarket removed before resolution (manual edit)\nMarket Definition\ninterface MarketDefinition {\n  id: string                  // unique market identifier\n  question: string            // human-readable question\n  symbol: string              // token symbol (max 10 chars)\n  name: string                // token name (max 32 chars)\n  oracle: Oracle              // how the market resolves\n  deadline: number            // unix timestamp (seconds)\n  initialLiquidityLamports: number  // SOL to seed bonding curve (in lamports, max 10 SOL)\n  metadataUri: string         // token metadata URI (allowlisted domains only)\n}\n\nInput Validation\n\nAll pending markets are validated on load. Markets with invalid inputs are rejected before any on-chain action.\n\nField\tConstraint\tRejected Example\nid\tMust be unique across all markets\tDuplicate \"sol-200-mar\"\nmetadataUri\tDomain must be in allowlist: arweave.net, gateway.irys.xyz, ipfs.io, cloudflare-ipfs.com, nftstorage.link, dweb.link\thttps://evil.com/payload.json\ninitialLiquidityLamports\tMax 10 SOL (10,000,000,000 lamports), non-negative\t50000000000 (50 SOL)\noracle.asset\tMust be in allowlist of known CoinGecko IDs (solana, bitcoin, ethereum, etc.)\t\"arbitrary-string\"\n\nThese constraints ensure a compromised markets.json cannot trigger arbitrary URI fetches, drain the vault, or make unintended API calls.\n\nOracle Resolution\nPrice Feed Oracle (CoinGecko)\n\nThe primary oracle. Fetches the current price of an asset and compares it against a target.\n\n{\n  \"type\": \"price_feed\",\n  \"asset\": \"solana\",\n  \"condition\": \"above\",\n  \"target\": 200\n}\n\nasset — CoinGecko asset ID (e.g. \"solana\", \"bitcoin\", \"ethereum\")\ncondition — \"above\" or \"below\"\ntarget — USD price threshold\nResolution: if condition is \"above\", outcome is \"yes\" when price > target, \"no\" otherwise\nManual Oracle\n\nFallback for markets that can't be resolved by a price feed.\n\n{\n  \"type\": \"manual\",\n  \"source\": \"Twitter announcement from @torch_market\"\n}\n\n\nResolution: edit markets.json directly — set \"status\": \"resolved\" and \"outcome\": \"yes\" or \"no\".\n\nVault Safety Model\n\nThe same seven guarantees from the Torch Market vault apply here:\n\nProperty\tGuarantee\nFull custody\tVault holds all SOL and all market tokens. Agent wallet holds nothing.\nClosed loop\tSeed liquidity SOL comes from vault, purchased tokens go to vault ATA. No leakage to agent.\nAuthority separation\tCreator (immutable PDA seed) vs Authority (transferable admin) vs Controller (disposable signer).\nOne link per wallet\tAgent can only belong to one vault. PDA uniqueness enforces this on-chain.\nPermissionless deposits\tAnyone can top up the vault. Hardware wallet deposits, agent creates markets.\nInstant revocation\tAuthority can unlink the agent at any time. One transaction.\nAuthority-only withdrawals\tOnly the vault authority can withdraw SOL or tokens. The agent cannot extract value.\nThe Closed Economic Loop for Market Creation\nDirection\tFlow\nSOL out\tVault → Bonding curve (seed liquidity buy)\nTokens in\tBonding curve → Vault ATA (purchased tokens)\nTreasury\t10% of each buy accumulates in token treasury\n\nThe vault's seed tokens remain on the bonding curve. Users trade against the curve. Treasury grows from fees. The authority can withdraw vault tokens or SOL at any time.\n\nSDK Functions Used\n\nThe bot uses a focused subset of the Torch SDK:\n\nFunction\tPurpose\ngetVault(connection, creator)\tVerify vault exists on startup\ngetVaultForWallet(connection, wallet)\tVerify agent is linked to vault\nbuildCreateTokenTransaction(connection, params)\tBuild token creation transaction for new market\nbuildBuyTransaction(connection, params)\tBuild vault-routed buy to seed initial liquidity\ngetToken(connection, mint)\tGet token price, volume, status for market snapshots\ngetHolders(connection, mint)\tGet holder count for market snapshots\nconfirmTransaction(connection, sig, wallet)\tConfirm transaction on-chain via RPC (verifies signer, checks Torch instructions)\nbuildCreateTokenTransaction Parameters\nconst { transaction, mint, mintKeypair } = await buildCreateTokenTransaction(connection, {\n  creator: agentPubkey,       // agent wallet (signer + fee payer)\n  name: \"SOL Above 200 March\", // token name (max 32 chars)\n  symbol: \"SOL200M\",           // token symbol (max 10 chars)\n  metadata_uri: \"https://arweave.net/...\",  // token metadata URI\n});\n\nbuildBuyTransaction Parameters\nconst { transaction, message } = await buildBuyTransaction(connection, {\n  mint: mintAddress,            // token to buy\n  buyer: agentPubkey,           // agent wallet (signer)\n  amount_sol: 100000000,        // 0.1 SOL in lamports\n  slippage_bps: 500,            // 5% slippage tolerance\n  vault: vaultCreator,          // vault creator pubkey (SOL from vault, tokens to vault ATA)\n});\n\nSigning & Key Safety\n\nThe vault is the security boundary, not the key.\n\nThe agent keypair is generated fresh on every startup with Keypair.generate(). It holds ~0.01 SOL for gas fees. If the key is compromised, the attacker gets:\n\nDust (the gas SOL)\nVault access that the authority revokes in one transaction\n\nThe agent never needs the authority's private key. The authority never needs the agent's private key. They share a vault, not keys.\n\nRules\nNever ask a user for their private key or seed phrase. The vault authority signs from their own device.\nNever log, print, store, or transmit private key material. The agent keypair exists only in runtime memory.\nNever embed keys in source code or logs. The agent pubkey is printed — the secret key is never exposed.\nUse a secure RPC endpoint. Default to a private RPC provider. Never use an unencrypted HTTP endpoint for mainnet transactions.\nRPC Timeout\n\nAll SDK calls are wrapped with a 30-second timeout (withTimeout in utils.ts). A hanging or unresponsive RPC endpoint cannot stall the bot indefinitely — the call rejects, the error is caught by the market cycle loop, and the bot continues to the next market or cycle.\n\nEnvironment Variables\nVariable\tRequired\tPurpose\nSOLANA_RPC_URL / RPC_URL\tYes\tSolana RPC endpoint (HTTPS)\nVAULT_CREATOR\tYes\tVault creator pubkey — identifies which vault the bot operates through\nSOLANA_PRIVATE_KEY\tNo\tOptional — if omitted, the bot generates a fresh keypair on startup (recommended)\nExternal Runtime Dependencies\n\nThe SDK and bot make outbound HTTPS requests to external services. The bot's runtime path contacts three of them:\n\nService\tPurpose\tWhen Called\tBot Uses?\nCoinGecko (api.coingecko.com)\tAsset price for oracle resolution + SOL/USD display\tcheckPriceFeed() in oracle.ts, getToken() in SDK\tYes — oracle resolution AND token queries\nIrys Gateway (gateway.irys.xyz)\tToken metadata fallback (name, symbol, image)\tgetToken() when on-chain metadata URI points to Irys\tYes — via getToken()\nSAID Protocol (api.saidprotocol.com)\tAgent identity verification and trust tier lookup\tverifySaid() only\tNo — the bot does not call verifySaid()\nCoinGecko API Details (Oracle)\n\nThe oracle module (oracle.ts) calls the CoinGecko public API directly:\n\nGET https://api.coingecko.com/api/v3/simple/price?ids={asset}&vs_currencies=usd\n\nNo API key required — uses the free public endpoint\nRate limit: ~10-30 calls/minute on the free tier\nData sent: asset ID only (e.g. \"solana\") — no wallet, transaction, or agent data\nData received: { \"solana\": { \"usd\": 87.76 } }\nFailure mode: if CoinGecko is unreachable, checkPriceFeed() throws and the market stays unresolved until the next cycle\nCalled once per active market per cycle that has passed its deadline\n\nconfirmTransaction() does NOT contact SAID. Despite living in the SDK's said.js module, it only calls connection.getParsedTransaction() (Solana RPC) to verify the transaction succeeded on-chain and determine the event type. No data is sent to any external service.\n\nNo credentials are sent to CoinGecko or Irys. All requests are read-only GET. If either service is unreachable, the bot degrades gracefully. No private key material is ever transmitted to any external endpoint.\n\nLog Output\n=== torch prediction market bot ===\nagent wallet: 7xK9...\nvault creator: 4yN2...\nmarkets file: ./markets.json\nscan interval: 60000ms\n\n[09:15:32] INFO  vault found — authority=8cpW...\n[09:15:32] INFO  agent wallet linked to vault — starting market cycle\n[09:15:32] INFO  treasury: 5.0000 SOL\n[09:15:33] INFO  CREATING | sol-200-mar — \"Will SOL be above $200 by March 1, 2026?\"\n[09:15:35] INFO  CREATED | sol-200-mar — mint=AqAgqKTypS... | seed=0.1000 SOL\n[09:16:35] DEBUG SNAPSHOT | sol-200-mar — price=0.000012 SOL | mcap=0.0120 | holders=3\n[09:17:35] INFO  RESOLVING | sol-200-mar — deadline reached\n[09:17:36] INFO  RESOLVED | sol-200-mar — outcome=no\n\nTesting\n\nRequires Surfpool running a mainnet fork:\n\nsurfpool start --network mainnet --no-tui\npnpm test\n\n\nTest result: 9 passed, 1 informational (Surfpool RPC limitation on getTokenLargestAccounts for Token-2022 — works on mainnet).\n\nTest\tWhat It Validates\nConnection\tRPC reachable\nloadMarkets\tMarket file parsing and validation\ncheckPriceFeed\tCoinGecko oracle returns valid price data\nbuildCreateTokenTransaction\tToken creation transaction builds correctly\ngetTokens\tDiscovers bonding/migrated tokens\ngetToken\tToken metadata, price, status\ngetHolders\tHolder enumeration (skips on Surfpool limitation)\ngetVaultForWallet\tVault link returns null for unlinked wallet\nIn-process keypair\tNo external key required\nError Codes\nVAULT_NOT_FOUND: No vault exists for this creator\nWALLET_NOT_LINKED: Agent wallet is not linked to the vault\nINVALID_MINT: Token not found\nBONDING_COMPLETE: Token has graduated — trade on DEX instead\nNAME_TOO_LONG: Token name exceeds 32 characters\nSYMBOL_TOO_LONG: Token symbol exceeds 10 characters\nLinks\nPrediction Market Kit (source): github.com/mrsirg97-rgb/torch-prediction-market-kit\nPrediction Market Kit (npm): npmjs.com/package/torch-prediction-market-kit\nTorch SDK (bundled): lib/torchsdk/ -- included in this skill\nTorch SDK (source): github.com/mrsirg97-rgb/torchsdk\nTorch SDK (npm): npmjs.com/package/torchsdk\nTorch Market (protocol skill): clawhub.ai/mrsirg97-rgb/torchmarket\nWhitepaper: torch.market/whitepaper.md\nSecurity Audit: torch.market/audit.md\nWebsite: torch.market\nProgram ID: 8hbUkonssSEEtkqzwM7ZcZrD9evacM92TcWSooVF4BeT\nChangelog\nv2.0.0\nUpgraded torchsdk from 3.2.3 to 3.7.23. Major SDK update adds treasury lock PDAs (V27), dynamic Raydium network detection, auto-migration bundling on bonding curve completion (buildBuyTransaction now returns optional migrationTransaction), vault-routed Raydium CPMM swaps (buildVaultSwapTransaction), Token-2022 fee harvesting (buildHarvestFeesTransaction, buildSwapFeesToSolTransaction), bulk loan scanning (getAllLoanPositions), on-chain token metadata queries (getTokenMetadata), and ephemeral agent keypair factory (createEphemeralAgent).\nExported withTimeout utility. The timeout helper used internally by the bot is now a public export of the kit package, available to downstream consumers.\nUpdated env format in skill frontmatter. Environment variable declarations now use structured name/required format for compatibility with ClawHub and OpenClaw agent runners.\nv1.0.2\nUpdated kit to point to correct bundled sdk. The index.js file now imports the SDK from the local lib/torchsdk/ directory instead of the npm package. This ensures that the bot uses the exact bundled SDK version (3.2.3) included in the kit, rather than any potentially different version installed from npm. Addresses audit finding L-3.\nv1.0.1\nTimeout on all external calls. Every SDK, RPC, and API call is now wrapped with a 30-second timeout (10 seconds for CoinGecko). If an RPC endpoint or CoinGecko becomes unresponsive, the call fails fast with a descriptive error instead of stalling the bot indefinitely. Addresses audit finding L-1.\nMarket ID uniqueness validation. loadMarkets() now rejects markets.json files containing duplicate market IDs on load, preventing unintended duplicate market creation and wasted vault SOL. Addresses audit finding L-2.\n\nThis bot exists because prediction markets need infrastructure. Torch bonding curves provide instant liquidity and deterministic pricing without LP setup. The vault makes it safe — all value stays in the escrow, all risk is bounded, and the human principal keeps the keys. The token price IS the prediction."
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/mrsirg97-rgb/torchpredictionmarketkit",
    "publisherUrl": "https://clawhub.ai/mrsirg97-rgb/torchpredictionmarketkit",
    "owner": "mrsirg97-rgb",
    "version": "2.0.3",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/torchpredictionmarketkit",
    "downloadUrl": "https://openagent3.xyz/downloads/torchpredictionmarketkit",
    "agentUrl": "https://openagent3.xyz/skills/torchpredictionmarketkit/agent",
    "manifestUrl": "https://openagent3.xyz/skills/torchpredictionmarketkit/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/torchpredictionmarketkit/agent.md"
  }
}