{"version":3,"file":"bankr-polymarket.mjs","names":[],"sources":["../../../src/tools/bankr-polymarket.ts"],"sourcesContent":["/**\n * Bankr Polymarket Tool — prediction markets via Bankr Agent API.\n *\n * Search markets, place bets, view positions, and redeem winnings.\n * All operations go through Bankr's prompt API. Executes on Polygon.\n * Requires Bankr wallet (/connect_bankr).\n */\n\nimport { Type } from '@sinclair/typebox';\nimport { stringEnum, jsonResult, errorResult, readStringParam } from '../lib/tool-helpers.js';\nimport { hasBankrApi } from '../services/bankr-api.js';\n\nconst ACTIONS = ['search', 'bet', 'positions', 'redeem'] as const;\n\nconst BankrPolymarketSchema = Type.Object({\n  action: stringEnum(ACTIONS, {\n    description:\n      'search: find prediction markets. bet: place a bet. ' +\n      'positions: view your current positions. redeem: claim winnings from resolved markets.',\n  }),\n  query: Type.Optional(Type.String({\n    description: 'Search query for finding markets (e.g. \"eagles win\", \"bitcoin price\", \"election\").',\n  })),\n  market: Type.Optional(Type.String({\n    description: 'Market description or ID to bet on.',\n  })),\n  outcome: Type.Optional(Type.String({\n    description: 'Outcome to bet on: \"yes\", \"no\", or a specific outcome name.',\n  })),\n  amount: Type.Optional(Type.String({\n    description: 'Dollar amount to bet (e.g. \"10\", \"50\").',\n  })),\n});\n\n// ─── Input Sanitization (C3: prevent prompt injection) ──────────────────\nconst SAFE_QUERY_RE = /^[a-zA-Z0-9 ?!,.\\-'\":;$%#@()]{1,200}$/;\nconst SAFE_AMOUNT_RE = /^\\$?[0-9][0-9,._]*$/;\nconst SAFE_OUTCOME_RE = /^[a-zA-Z0-9 .\\-]{1,60}$/;\n\nfunction sanitizeQuery(input: string): string {\n  const trimmed = input.trim();\n  if (SAFE_QUERY_RE.test(trimmed)) return trimmed;\n  throw new Error(`Invalid query: contains disallowed characters. Keep it to simple text.`);\n}\nfunction sanitizeMarket(input: string): string {\n  const trimmed = input.trim();\n  if (SAFE_QUERY_RE.test(trimmed)) return trimmed;\n  throw new Error(`Invalid market: contains disallowed characters.`);\n}\nfunction sanitizeOutcome(input: string): string {\n  const trimmed = input.trim();\n  if (SAFE_OUTCOME_RE.test(trimmed)) return trimmed;\n  throw new Error(`Invalid outcome: \"${trimmed.slice(0, 20)}\". Use \"yes\", \"no\", or a simple name.`);\n}\nfunction sanitizeAmount(input: string): string {\n  const trimmed = input.trim();\n  if (SAFE_AMOUNT_RE.test(trimmed)) return trimmed;\n  throw new Error(`Invalid amount: \"${trimmed.slice(0, 20)}\". Use a number like \"10\" or \"50\".`);\n}\n\nfunction buildPrompt(action: string, params: Record<string, unknown>): string {\n  const query = readStringParam(params, 'query') ? sanitizeQuery(readStringParam(params, 'query')!) : '';\n  const market = readStringParam(params, 'market') ? sanitizeMarket(readStringParam(params, 'market')!) : '';\n  const outcome = readStringParam(params, 'outcome') ? sanitizeOutcome(readStringParam(params, 'outcome')!) : '';\n  const amount = readStringParam(params, 'amount') ? sanitizeAmount(readStringParam(params, 'amount')!) : '';\n\n  switch (action) {\n    case 'search':\n      return `search polymarket for ${query}`;\n    case 'bet':\n      return `bet $${amount} on ${outcome} for ${market}`;\n    case 'positions':\n      return 'show my Polymarket positions';\n    case 'redeem':\n      return 'redeem my winning polymarket positions';\n    default:\n      return action;\n  }\n}\n\nexport function createBankrPolymarketTool() {\n  return {\n    name: 'bankr_polymarket',\n    label: 'Bankr Polymarket',\n    ownerOnly: true,\n    description:\n      'Prediction markets via Polymarket. Search for markets on any topic, ' +\n      'place bets (yes/no), view your positions, and redeem winnings. ' +\n      'Executes on Polygon via Bankr. Requires Bankr wallet (/connect_bankr).',\n    parameters: BankrPolymarketSchema,\n    execute: async (_toolCallId: string, args: unknown) => {\n      const params = args as Record<string, unknown>;\n      const action = readStringParam(params, 'action', { required: true })!;\n\n      if (!hasBankrApi()) {\n        return errorResult(\n          'Bankr API key not configured. Connect via /connect_bankr first.'\n        );\n      }\n\n      // Validate required params\n      if (action === 'search' && !readStringParam(params, 'query')) {\n        return errorResult('\"query\" is required for search (e.g. \"Will Bitcoin reach $100k?\").');\n      }\n      if (action === 'bet') {\n        if (!readStringParam(params, 'market')) {\n          return errorResult('\"market\" is required for bet. Search for markets first.');\n        }\n        if (!readStringParam(params, 'outcome')) {\n          return errorResult('\"outcome\" is required for bet (e.g. \"yes\" or \"no\").');\n        }\n        if (!readStringParam(params, 'amount')) {\n          return errorResult('\"amount\" is required for bet (dollar amount).');\n        }\n      }\n\n      try {\n        const { bankrPromptAndPoll } = await import('../services/bankr-api.js');\n\n        const prompt = buildPrompt(action, params);\n        const timeoutMs = action === 'search' || action === 'positions' ? 30_000 : 60_000;\n        const result = await bankrPromptAndPoll(prompt, { timeoutMs });\n\n        if (result.status === 'failed') {\n          return errorResult(`Polymarket ${action} failed: ${result.error ?? 'Unknown error'}`);\n        }\n\n        return jsonResult({\n          status: 'success',\n          action,\n          chain: 'polygon',\n          response: result.response,\n          richData: result.richData,\n          transactions: result.transactions,\n        });\n      } catch (err) {\n        return errorResult(\n          `Polymarket ${action} failed: ${err instanceof Error ? err.message : String(err)}`\n        );\n      }\n    },\n  };\n}\n"],"mappings":"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"}