chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
import type { PolymarketActivity } from '@/tools/polymarket/types'
|
||||
import { buildDataUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetActivityParams {
|
||||
user: string
|
||||
limit?: string
|
||||
offset?: string
|
||||
market?: string
|
||||
eventId?: string
|
||||
type?: string
|
||||
start?: number
|
||||
end?: number
|
||||
sortBy?: string
|
||||
sortDirection?: string
|
||||
side?: string
|
||||
}
|
||||
|
||||
export interface PolymarketGetActivityResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
activity: PolymarketActivity[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetActivityTool: ToolConfig<
|
||||
PolymarketGetActivityParams,
|
||||
PolymarketGetActivityResponse
|
||||
> = {
|
||||
id: 'polymarket_get_activity',
|
||||
name: 'Get Activity from Polymarket',
|
||||
description:
|
||||
'Retrieve on-chain activity for a user including trades, splits, merges, redemptions, rewards, and conversions',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
user: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'User wallet address (0x-prefixed)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Maximum results to return (e.g., "50"). Default: 100, max: 500.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
offset: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Number of results to skip for pagination (e.g., "100"). Default: 0, max: 10000.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
market: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Comma-separated condition IDs (e.g., "0x1234...abcd,0x5678...efgh"). Mutually exclusive with eventId.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
eventId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Comma-separated event IDs (e.g., "12345,67890"). Mutually exclusive with market.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Activity type filter: TRADE, SPLIT, MERGE, REDEEM, REWARD, CONVERSION, MAKER_REBATE, REFERRAL_REWARD',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
start: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'Start timestamp (Unix seconds)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
end: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'End timestamp (Unix seconds)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
sortBy: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Sort field: TIMESTAMP, TOKENS, or CASH (default: TIMESTAMP)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
sortDirection: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Sort direction: ASC or DESC (default: DESC)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
side: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Trade side filter: BUY or SELL (only applies to trades)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('user', params.user)
|
||||
if (params.limit) queryParams.append('limit', params.limit)
|
||||
if (params.offset) queryParams.append('offset', params.offset)
|
||||
if (params.market) queryParams.append('market', params.market)
|
||||
if (params.eventId) queryParams.append('eventId', params.eventId)
|
||||
if (params.type) queryParams.append('type', params.type)
|
||||
if (params.start != null && !Number.isNaN(params.start))
|
||||
queryParams.append('start', String(params.start))
|
||||
if (params.end != null && !Number.isNaN(params.end))
|
||||
queryParams.append('end', String(params.end))
|
||||
if (params.sortBy) queryParams.append('sortBy', params.sortBy)
|
||||
if (params.sortDirection) queryParams.append('sortDirection', params.sortDirection)
|
||||
if (params.side) queryParams.append('side', params.side)
|
||||
return `${buildDataUrl('/activity')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_activity')
|
||||
}
|
||||
|
||||
const activityList = Array.isArray(data) ? data : []
|
||||
|
||||
const activity: PolymarketActivity[] = activityList.map((a: any) => ({
|
||||
proxyWallet: a.proxyWallet ?? null,
|
||||
timestamp: a.timestamp ?? 0,
|
||||
conditionId: a.conditionId ?? '',
|
||||
type: a.type ?? '',
|
||||
size: a.size ?? 0,
|
||||
usdcSize: a.usdcSize ?? 0,
|
||||
transactionHash: a.transactionHash ?? null,
|
||||
price: a.price ?? null,
|
||||
asset: a.asset ?? null,
|
||||
side: a.side ?? null,
|
||||
outcomeIndex: a.outcomeIndex ?? null,
|
||||
title: a.title ?? null,
|
||||
slug: a.slug ?? null,
|
||||
icon: a.icon ?? null,
|
||||
eventSlug: a.eventSlug ?? null,
|
||||
outcome: a.outcome ?? null,
|
||||
name: a.name ?? null,
|
||||
pseudonym: a.pseudonym ?? null,
|
||||
bio: a.bio ?? null,
|
||||
profileImage: a.profileImage ?? null,
|
||||
profileImageOptimized: a.profileImageOptimized ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
activity,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
activity: {
|
||||
type: 'array',
|
||||
description: 'Array of activity entries',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
proxyWallet: { type: 'string', description: 'User proxy wallet address' },
|
||||
timestamp: { type: 'number', description: 'Unix timestamp of activity' },
|
||||
conditionId: { type: 'string', description: 'Market condition ID' },
|
||||
type: {
|
||||
type: 'string',
|
||||
description: 'Activity type (TRADE, SPLIT, MERGE, REDEEM, REWARD, CONVERSION)',
|
||||
},
|
||||
size: { type: 'number', description: 'Size in tokens' },
|
||||
usdcSize: { type: 'number', description: 'Size in USDC' },
|
||||
transactionHash: { type: 'string', description: 'Blockchain transaction hash' },
|
||||
price: { type: 'number', description: 'Price (for trades)' },
|
||||
asset: { type: 'string', description: 'Asset/token ID' },
|
||||
side: { type: 'string', description: 'Trade side (BUY/SELL)' },
|
||||
outcomeIndex: { type: 'number', description: 'Outcome index' },
|
||||
title: { type: 'string', description: 'Market title' },
|
||||
slug: { type: 'string', description: 'Market slug' },
|
||||
icon: { type: 'string', description: 'Market icon URL' },
|
||||
eventSlug: { type: 'string', description: 'Event slug' },
|
||||
outcome: { type: 'string', description: 'Outcome name' },
|
||||
name: { type: 'string', description: 'User display name' },
|
||||
pseudonym: { type: 'string', description: 'User pseudonym' },
|
||||
bio: { type: 'string', description: 'User bio' },
|
||||
profileImage: { type: 'string', description: 'User profile image URL' },
|
||||
profileImageOptimized: { type: 'string', description: 'Optimized profile image URL' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import type { PolymarketEvent } from '@/tools/polymarket/types'
|
||||
import { buildGammaUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetEventParams {
|
||||
eventId?: string // Event ID
|
||||
slug?: string // Event slug (alternative to ID)
|
||||
}
|
||||
|
||||
export interface PolymarketGetEventResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
event: PolymarketEvent
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetEventTool: ToolConfig<
|
||||
PolymarketGetEventParams,
|
||||
PolymarketGetEventResponse
|
||||
> = {
|
||||
id: 'polymarket_get_event',
|
||||
name: 'Get Event from Polymarket',
|
||||
description: 'Retrieve details of a specific event by ID or slug',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
eventId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'The numeric event ID (e.g., "12345"). Required if slug is not provided.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'The event slug (e.g., "2024-presidential-election"). URL-friendly identifier. Required if eventId is not provided.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
if (params.slug) {
|
||||
return buildGammaUrl(`/events/slug/${params.slug.trim()}`)
|
||||
}
|
||||
return buildGammaUrl(`/events/${params.eventId?.trim()}`)
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_event')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
event: data,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
event: {
|
||||
type: 'object',
|
||||
description: 'Event object with details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Event ID' },
|
||||
ticker: { type: 'string', description: 'Event ticker' },
|
||||
slug: { type: 'string', description: 'Event slug' },
|
||||
title: { type: 'string', description: 'Event title' },
|
||||
description: { type: 'string', description: 'Event description' },
|
||||
startDate: { type: 'string', description: 'Start date' },
|
||||
creationDate: { type: 'string', description: 'Creation date' },
|
||||
endDate: { type: 'string', description: 'End date' },
|
||||
image: { type: 'string', description: 'Event image URL' },
|
||||
icon: { type: 'string', description: 'Event icon URL' },
|
||||
active: { type: 'boolean', description: 'Whether event is active' },
|
||||
closed: { type: 'boolean', description: 'Whether event is closed' },
|
||||
archived: { type: 'boolean', description: 'Whether event is archived' },
|
||||
liquidity: { type: 'number', description: 'Total liquidity' },
|
||||
volume: { type: 'number', description: 'Total volume' },
|
||||
openInterest: { type: 'number', description: 'Open interest' },
|
||||
commentCount: { type: 'number', description: 'Comment count' },
|
||||
markets: { type: 'array', description: 'Array of markets in this event' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
import type { PolymarketEvent, PolymarketPaginationParams } from '@/tools/polymarket/types'
|
||||
import { buildGammaUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetEventsParams extends PolymarketPaginationParams {
|
||||
closed?: string
|
||||
order?: string
|
||||
ascending?: string
|
||||
tagId?: string
|
||||
}
|
||||
|
||||
export interface PolymarketGetEventsResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
events: PolymarketEvent[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetEventsTool: ToolConfig<
|
||||
PolymarketGetEventsParams,
|
||||
PolymarketGetEventsResponse
|
||||
> = {
|
||||
id: 'polymarket_get_events',
|
||||
name: 'Get Events from Polymarket',
|
||||
description: 'Retrieve a list of events from Polymarket with optional filtering',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
closed: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter by closed status (true/false). Use false for open events only.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
order: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Sort field (e.g., volume, liquidity, startDate, endDate, createdAt)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
ascending: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Sort direction (true for ascending, false for descending)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
tagId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter by tag ID',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results per page (e.g., "25"). Max: 50.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
offset: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results to skip for pagination (e.g., "50").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.closed) queryParams.append('closed', params.closed)
|
||||
if (params.order) queryParams.append('order', params.order)
|
||||
if (params.ascending) queryParams.append('ascending', params.ascending)
|
||||
if (params.tagId) queryParams.append('tag_id', params.tagId)
|
||||
queryParams.append('limit', params.limit || '50')
|
||||
if (params.offset) queryParams.append('offset', params.offset)
|
||||
|
||||
const url = buildGammaUrl('/events')
|
||||
return `${url}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_events')
|
||||
}
|
||||
|
||||
const events = Array.isArray(data) ? data : []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
events,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
events: {
|
||||
type: 'array',
|
||||
description: 'Array of event objects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Event ID' },
|
||||
ticker: { type: 'string', description: 'Event ticker' },
|
||||
slug: { type: 'string', description: 'Event slug' },
|
||||
title: { type: 'string', description: 'Event title' },
|
||||
description: { type: 'string', description: 'Event description' },
|
||||
startDate: { type: 'string', description: 'Start date' },
|
||||
endDate: { type: 'string', description: 'End date' },
|
||||
image: { type: 'string', description: 'Event image URL' },
|
||||
icon: { type: 'string', description: 'Event icon URL' },
|
||||
active: { type: 'boolean', description: 'Whether event is active' },
|
||||
closed: { type: 'boolean', description: 'Whether event is closed' },
|
||||
archived: { type: 'boolean', description: 'Whether event is archived' },
|
||||
liquidity: { type: 'number', description: 'Total liquidity' },
|
||||
volume: { type: 'number', description: 'Total volume' },
|
||||
markets: { type: 'array', description: 'Array of markets in this event' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
import type { PolymarketMarketHolders } from '@/tools/polymarket/types'
|
||||
import { buildDataUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetHoldersParams {
|
||||
market: string
|
||||
limit?: string
|
||||
minBalance?: string
|
||||
}
|
||||
|
||||
export interface PolymarketGetHoldersResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
holders: PolymarketMarketHolders[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetHoldersTool: ToolConfig<
|
||||
PolymarketGetHoldersParams,
|
||||
PolymarketGetHoldersResponse
|
||||
> = {
|
||||
id: 'polymarket_get_holders',
|
||||
name: 'Get Market Holders from Polymarket',
|
||||
description: 'Retrieve top holders of a specific market token',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
market: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description:
|
||||
'Comma-separated list of condition IDs (e.g., "0x1234...abcd" or "0x1234...abcd,0x5678...efgh").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of holders to return (e.g., "10"). Range: 0-20, default: 20.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
minBalance: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Minimum balance threshold (default: 1)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('market', params.market)
|
||||
if (params.limit) queryParams.append('limit', params.limit)
|
||||
if (params.minBalance) queryParams.append('minBalance', params.minBalance)
|
||||
return `${buildDataUrl('/holders')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_holders')
|
||||
}
|
||||
|
||||
const marketHolders = Array.isArray(data) ? data : []
|
||||
|
||||
const holders: PolymarketMarketHolders[] = marketHolders.map((mh: any) => ({
|
||||
token: mh.token ?? '',
|
||||
holders: (mh.holders ?? []).map((h: any) => ({
|
||||
proxyWallet: h.proxyWallet ?? '',
|
||||
bio: h.bio ?? null,
|
||||
asset: h.asset ?? '',
|
||||
pseudonym: h.pseudonym ?? null,
|
||||
amount: h.amount ?? 0,
|
||||
displayUsernamePublic: h.displayUsernamePublic ?? false,
|
||||
outcomeIndex: h.outcomeIndex ?? 0,
|
||||
name: h.name ?? null,
|
||||
profileImage: h.profileImage ?? null,
|
||||
profileImageOptimized: h.profileImageOptimized ?? null,
|
||||
verified: h.verified ?? false,
|
||||
})),
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
holders,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
holders: {
|
||||
type: 'array',
|
||||
description: 'Array of market holder groups by token',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
token: { type: 'string', description: 'Token/asset ID' },
|
||||
holders: {
|
||||
type: 'array',
|
||||
description: 'Array of holders for this token',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
proxyWallet: { type: 'string', description: 'Holder wallet address' },
|
||||
bio: { type: 'string', description: 'Holder bio' },
|
||||
asset: { type: 'string', description: 'Asset ID' },
|
||||
pseudonym: { type: 'string', description: 'Holder pseudonym' },
|
||||
amount: { type: 'number', description: 'Amount held' },
|
||||
displayUsernamePublic: {
|
||||
type: 'boolean',
|
||||
description: 'Whether username is publicly displayed',
|
||||
},
|
||||
outcomeIndex: { type: 'number', description: 'Outcome index' },
|
||||
name: { type: 'string', description: 'Holder display name' },
|
||||
profileImage: { type: 'string', description: 'Profile image URL' },
|
||||
profileImageOptimized: {
|
||||
type: 'string',
|
||||
description: 'Optimized profile image URL',
|
||||
},
|
||||
verified: { type: 'boolean', description: 'Whether the holder is verified' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { buildClobUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetLastTradePriceParams {
|
||||
tokenId: string // The token ID (CLOB token ID from market)
|
||||
}
|
||||
|
||||
export interface PolymarketGetLastTradePriceResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
price: string
|
||||
side: string
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetLastTradePriceTool: ToolConfig<
|
||||
PolymarketGetLastTradePriceParams,
|
||||
PolymarketGetLastTradePriceResponse
|
||||
> = {
|
||||
id: 'polymarket_get_last_trade_price',
|
||||
name: 'Get Last Trade Price from Polymarket',
|
||||
description: 'Retrieve the last trade price for a specific token',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
tokenId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description:
|
||||
'The CLOB token ID from market clobTokenIds array (e.g., "71321045679252212594626385532706912750332728571942532289631379312455583992563").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('token_id', params.tokenId)
|
||||
return `${buildClobUrl('/last-trade-price')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_last_trade_price')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
price: data.price ?? '',
|
||||
side: data.side ?? '',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
price: {
|
||||
type: 'string',
|
||||
description: 'Last trade price',
|
||||
},
|
||||
side: {
|
||||
type: 'string',
|
||||
description: 'Side of the last trade (BUY or SELL)',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
import type { PolymarketLeaderboardEntry } from '@/tools/polymarket/types'
|
||||
import { buildDataUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetLeaderboardParams {
|
||||
category?: string
|
||||
timePeriod?: string
|
||||
orderBy?: string
|
||||
limit?: string
|
||||
offset?: string
|
||||
user?: string
|
||||
userName?: string
|
||||
}
|
||||
|
||||
export interface PolymarketGetLeaderboardResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
leaderboard: PolymarketLeaderboardEntry[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetLeaderboardTool: ToolConfig<
|
||||
PolymarketGetLeaderboardParams,
|
||||
PolymarketGetLeaderboardResponse
|
||||
> = {
|
||||
id: 'polymarket_get_leaderboard',
|
||||
name: 'Get Leaderboard from Polymarket',
|
||||
description: 'Retrieve trader leaderboard rankings by profit/loss or volume',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
category: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Category filter: OVERALL, POLITICS, SPORTS, CRYPTO, CULTURE, MENTIONS, WEATHER, ECONOMICS, TECH, FINANCE (default: OVERALL)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
timePeriod: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Time period: DAY, WEEK, MONTH, ALL (default: DAY)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
orderBy: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Order by: PNL or VOL (default: PNL)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results to return (e.g., "10"). Range: 1-50, default: 25.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
offset: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Number of results to skip for pagination (e.g., "25"). Range: 0-1000, default: 0.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
user: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter by specific user wallet address',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
userName: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter by username',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.category) queryParams.append('category', params.category)
|
||||
if (params.timePeriod) queryParams.append('timePeriod', params.timePeriod)
|
||||
if (params.orderBy) queryParams.append('orderBy', params.orderBy)
|
||||
if (params.limit) queryParams.append('limit', params.limit)
|
||||
if (params.offset) queryParams.append('offset', params.offset)
|
||||
if (params.user) queryParams.append('user', params.user)
|
||||
if (params.userName) queryParams.append('userName', params.userName)
|
||||
const query = queryParams.toString()
|
||||
return query ? `${buildDataUrl('/v1/leaderboard')}?${query}` : buildDataUrl('/v1/leaderboard')
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_leaderboard')
|
||||
}
|
||||
|
||||
const entries = Array.isArray(data) ? data : []
|
||||
|
||||
const leaderboard: PolymarketLeaderboardEntry[] = entries.map((entry: any) => ({
|
||||
rank: entry.rank ?? '',
|
||||
proxyWallet: entry.proxyWallet ?? '',
|
||||
userName: entry.userName ?? null,
|
||||
vol: entry.vol ?? 0,
|
||||
pnl: entry.pnl ?? 0,
|
||||
profileImage: entry.profileImage ?? null,
|
||||
xUsername: entry.xUsername ?? null,
|
||||
verifiedBadge: entry.verifiedBadge ?? false,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
leaderboard,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
leaderboard: {
|
||||
type: 'array',
|
||||
description: 'Array of leaderboard entries',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
rank: { type: 'string', description: 'Leaderboard rank position' },
|
||||
proxyWallet: { type: 'string', description: 'User proxy wallet address' },
|
||||
userName: { type: 'string', description: 'User display name' },
|
||||
vol: { type: 'number', description: 'Trading volume' },
|
||||
pnl: { type: 'number', description: 'Profit and loss' },
|
||||
profileImage: { type: 'string', description: 'User profile image URL' },
|
||||
xUsername: { type: 'string', description: 'Twitter/X username' },
|
||||
verifiedBadge: { type: 'boolean', description: 'Whether user has verified badge' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import type { PolymarketMarket } from '@/tools/polymarket/types'
|
||||
import { buildGammaUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetMarketParams {
|
||||
marketId?: string // Market ID
|
||||
slug?: string // Market slug (alternative to ID)
|
||||
}
|
||||
|
||||
export interface PolymarketGetMarketResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
market: PolymarketMarket
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetMarketTool: ToolConfig<
|
||||
PolymarketGetMarketParams,
|
||||
PolymarketGetMarketResponse
|
||||
> = {
|
||||
id: 'polymarket_get_market',
|
||||
name: 'Get Market from Polymarket',
|
||||
description: 'Retrieve details of a specific prediction market by ID or slug',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
marketId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'The numeric market ID (e.g., "253591"). Required if slug is not provided. Not the condition ID.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
slug: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'The market slug (e.g., "will-trump-win"). URL-friendly identifier. Required if marketId is not provided.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
if (params.slug) {
|
||||
return buildGammaUrl(`/markets/slug/${params.slug.trim()}`)
|
||||
}
|
||||
return buildGammaUrl(`/markets/${params.marketId?.trim()}`)
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_market')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
market: data,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
market: {
|
||||
type: 'object',
|
||||
description: 'Market object with details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Market ID' },
|
||||
question: { type: 'string', description: 'Market question' },
|
||||
conditionId: { type: 'string', description: 'Condition ID' },
|
||||
slug: { type: 'string', description: 'Market slug' },
|
||||
resolutionSource: { type: 'string', description: 'Resolution source' },
|
||||
endDate: { type: 'string', description: 'End date' },
|
||||
startDate: { type: 'string', description: 'Start date' },
|
||||
image: { type: 'string', description: 'Market image URL' },
|
||||
icon: { type: 'string', description: 'Market icon URL' },
|
||||
description: { type: 'string', description: 'Market description' },
|
||||
outcomes: { type: 'string', description: 'Outcomes JSON string' },
|
||||
outcomePrices: { type: 'string', description: 'Outcome prices JSON string' },
|
||||
volume: { type: 'string', description: 'Total volume' },
|
||||
liquidity: { type: 'string', description: 'Total liquidity' },
|
||||
active: { type: 'boolean', description: 'Whether market is active' },
|
||||
closed: { type: 'boolean', description: 'Whether market is closed' },
|
||||
archived: { type: 'boolean', description: 'Whether market is archived' },
|
||||
volumeNum: { type: 'number', description: 'Volume as number' },
|
||||
liquidityNum: { type: 'number', description: 'Liquidity as number' },
|
||||
clobTokenIds: { type: 'array', description: 'CLOB token IDs' },
|
||||
acceptingOrders: { type: 'boolean', description: 'Whether accepting orders' },
|
||||
negRisk: { type: 'boolean', description: 'Whether negative risk' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
import type { PolymarketMarket, PolymarketPaginationParams } from '@/tools/polymarket/types'
|
||||
import { buildGammaUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetMarketsParams extends PolymarketPaginationParams {
|
||||
closed?: string
|
||||
order?: string
|
||||
ascending?: string
|
||||
tagId?: string
|
||||
}
|
||||
|
||||
export interface PolymarketGetMarketsResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
markets: PolymarketMarket[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetMarketsTool: ToolConfig<
|
||||
PolymarketGetMarketsParams,
|
||||
PolymarketGetMarketsResponse
|
||||
> = {
|
||||
id: 'polymarket_get_markets',
|
||||
name: 'Get Markets from Polymarket',
|
||||
description: 'Retrieve a list of prediction markets from Polymarket with optional filtering',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
closed: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter by closed status (true/false). Use false for open markets only.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
order: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Sort field (e.g., volumeNum, liquidityNum, startDate, endDate, createdAt)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
ascending: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Sort direction (true for ascending, false for descending)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
tagId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter by tag ID',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results per page (e.g., "25"). Max: 50.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
offset: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results to skip for pagination (e.g., "50").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.closed) queryParams.append('closed', params.closed)
|
||||
if (params.order) queryParams.append('order', params.order)
|
||||
if (params.ascending) queryParams.append('ascending', params.ascending)
|
||||
if (params.tagId) queryParams.append('tag_id', params.tagId)
|
||||
queryParams.append('limit', params.limit || '50')
|
||||
if (params.offset) queryParams.append('offset', params.offset)
|
||||
|
||||
const url = buildGammaUrl('/markets')
|
||||
return `${url}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_markets')
|
||||
}
|
||||
|
||||
// Response is an array of markets
|
||||
const markets = Array.isArray(data) ? data : []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
markets,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
markets: {
|
||||
type: 'array',
|
||||
description: 'Array of market objects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Market ID' },
|
||||
question: { type: 'string', description: 'Market question' },
|
||||
conditionId: { type: 'string', description: 'Condition ID' },
|
||||
slug: { type: 'string', description: 'Market slug' },
|
||||
endDate: { type: 'string', description: 'End date' },
|
||||
image: { type: 'string', description: 'Market image URL' },
|
||||
outcomes: { type: 'string', description: 'Outcomes JSON string' },
|
||||
outcomePrices: { type: 'string', description: 'Outcome prices JSON string' },
|
||||
volume: { type: 'string', description: 'Total volume' },
|
||||
liquidity: { type: 'string', description: 'Total liquidity' },
|
||||
active: { type: 'boolean', description: 'Whether market is active' },
|
||||
closed: { type: 'boolean', description: 'Whether market is closed' },
|
||||
volumeNum: { type: 'number', description: 'Volume as number' },
|
||||
liquidityNum: { type: 'number', description: 'Liquidity as number' },
|
||||
clobTokenIds: { type: 'array', description: 'CLOB token IDs' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import { buildClobUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetMidpointParams {
|
||||
tokenId: string // The token ID (CLOB token ID from market)
|
||||
}
|
||||
|
||||
export interface PolymarketGetMidpointResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
midpoint: string
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetMidpointTool: ToolConfig<
|
||||
PolymarketGetMidpointParams,
|
||||
PolymarketGetMidpointResponse
|
||||
> = {
|
||||
id: 'polymarket_get_midpoint',
|
||||
name: 'Get Midpoint Price from Polymarket',
|
||||
description: 'Retrieve the midpoint price for a specific token',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
tokenId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description:
|
||||
'The CLOB token ID from market clobTokenIds array (e.g., "71321045679252212594626385532706912750332728571942532289631379312455583992563").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('token_id', params.tokenId)
|
||||
return `${buildClobUrl('/midpoint')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_midpoint')
|
||||
}
|
||||
|
||||
// CLOB /midpoint returns { mid: "0.52" } (docs label it mid_price — handle both)
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
midpoint: String(data.mid ?? data.mid_price ?? data.midpoint ?? ''),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
midpoint: {
|
||||
type: 'string',
|
||||
description: 'Midpoint price',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import type { PolymarketOrderBook } from '@/tools/polymarket/types'
|
||||
import { buildClobUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetOrderbookParams {
|
||||
tokenId: string // The token ID (CLOB token ID from market)
|
||||
}
|
||||
|
||||
export interface PolymarketGetOrderbookResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
orderbook: PolymarketOrderBook
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetOrderbookTool: ToolConfig<
|
||||
PolymarketGetOrderbookParams,
|
||||
PolymarketGetOrderbookResponse
|
||||
> = {
|
||||
id: 'polymarket_get_orderbook',
|
||||
name: 'Get Orderbook from Polymarket',
|
||||
description: 'Retrieve the order book summary for a specific token',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
tokenId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description:
|
||||
'The CLOB token ID from market clobTokenIds array (e.g., "71321045679252212594626385532706912750332728571942532289631379312455583992563").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('token_id', params.tokenId)
|
||||
return `${buildClobUrl('/book')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_orderbook')
|
||||
}
|
||||
|
||||
const orderbook: PolymarketOrderBook = {
|
||||
market: data.market ?? '',
|
||||
asset_id: data.asset_id ?? '',
|
||||
hash: data.hash ?? '',
|
||||
timestamp: data.timestamp ?? '',
|
||||
bids: data.bids ?? [],
|
||||
asks: data.asks ?? [],
|
||||
min_order_size: data.min_order_size ?? '0',
|
||||
tick_size: data.tick_size ?? '0',
|
||||
neg_risk: data.neg_risk ?? false,
|
||||
last_trade_price: String(data.last_trade_price ?? ''),
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
orderbook,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
orderbook: {
|
||||
type: 'object',
|
||||
description: 'Order book with bids and asks arrays',
|
||||
properties: {
|
||||
market: { type: 'string', description: 'Market identifier' },
|
||||
asset_id: { type: 'string', description: 'Asset token ID' },
|
||||
hash: { type: 'string', description: 'Order book hash' },
|
||||
timestamp: { type: 'string', description: 'Timestamp' },
|
||||
bids: {
|
||||
type: 'array',
|
||||
description: 'Bid orders',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
price: { type: 'string', description: 'Bid price' },
|
||||
size: { type: 'string', description: 'Bid size' },
|
||||
},
|
||||
},
|
||||
},
|
||||
asks: {
|
||||
type: 'array',
|
||||
description: 'Ask orders',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
price: { type: 'string', description: 'Ask price' },
|
||||
size: { type: 'string', description: 'Ask size' },
|
||||
},
|
||||
},
|
||||
},
|
||||
min_order_size: { type: 'string', description: 'Minimum order size' },
|
||||
tick_size: { type: 'string', description: 'Tick size' },
|
||||
neg_risk: { type: 'boolean', description: 'Whether negative risk' },
|
||||
last_trade_price: { type: 'string', description: 'Last trade price' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
import type { PolymarketPosition } from '@/tools/polymarket/types'
|
||||
import { buildDataUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetPositionsParams {
|
||||
user: string
|
||||
market?: string
|
||||
eventId?: string
|
||||
sizeThreshold?: string
|
||||
redeemable?: string
|
||||
mergeable?: string
|
||||
sortBy?: string
|
||||
sortDirection?: string
|
||||
title?: string
|
||||
limit?: string
|
||||
offset?: string
|
||||
}
|
||||
|
||||
export interface PolymarketGetPositionsResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
positions: PolymarketPosition[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetPositionsTool: ToolConfig<
|
||||
PolymarketGetPositionsParams,
|
||||
PolymarketGetPositionsResponse
|
||||
> = {
|
||||
id: 'polymarket_get_positions',
|
||||
name: 'Get Positions from Polymarket',
|
||||
description: 'Retrieve user positions from Polymarket',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
user: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'User wallet address',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
market: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Condition IDs to filter positions (e.g., "0x1234...abcd,0x5678...efgh"). Mutually exclusive with eventId.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
eventId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Event ID to filter positions (e.g., "12345"). Mutually exclusive with market.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
sizeThreshold: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Minimum position size threshold (default: 1)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
redeemable: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter for redeemable positions only (true/false)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
mergeable: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter for mergeable positions only (true/false)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
sortBy: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Sort field (TOKENS, CURRENT, INITIAL, CASHPNL, PERCENTPNL, TITLE, RESOLVING, PRICE, AVGPRICE)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
sortDirection: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Sort direction (ASC or DESC)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Search filter by title',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results per page (e.g., "25").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
offset: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results to skip for pagination (e.g., "50").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('user', params.user)
|
||||
if (params.market) queryParams.append('market', params.market)
|
||||
if (params.eventId) queryParams.append('eventId', params.eventId)
|
||||
if (params.sizeThreshold) queryParams.append('sizeThreshold', params.sizeThreshold)
|
||||
if (params.redeemable) queryParams.append('redeemable', params.redeemable)
|
||||
if (params.mergeable) queryParams.append('mergeable', params.mergeable)
|
||||
if (params.sortBy) queryParams.append('sortBy', params.sortBy)
|
||||
if (params.sortDirection) queryParams.append('sortDirection', params.sortDirection)
|
||||
if (params.title) queryParams.append('title', params.title)
|
||||
if (params.limit) queryParams.append('limit', params.limit)
|
||||
if (params.offset) queryParams.append('offset', params.offset)
|
||||
|
||||
return `${buildDataUrl('/positions')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_positions')
|
||||
}
|
||||
|
||||
const rawPositions = Array.isArray(data) ? data : []
|
||||
const positions: PolymarketPosition[] = rawPositions.map((p: Record<string, unknown>) => ({
|
||||
proxyWallet: (p.proxyWallet as string) ?? null,
|
||||
asset: (p.asset as string) ?? '',
|
||||
conditionId: (p.conditionId as string) ?? '',
|
||||
size: (p.size as number) ?? 0,
|
||||
avgPrice: (p.avgPrice as number) ?? 0,
|
||||
initialValue: (p.initialValue as number) ?? 0,
|
||||
currentValue: (p.currentValue as number) ?? 0,
|
||||
cashPnl: (p.cashPnl as number) ?? 0,
|
||||
percentPnl: (p.percentPnl as number) ?? 0,
|
||||
totalBought: (p.totalBought as number) ?? 0,
|
||||
realizedPnl: (p.realizedPnl as number) ?? 0,
|
||||
percentRealizedPnl: (p.percentRealizedPnl as number) ?? 0,
|
||||
curPrice: (p.curPrice as number) ?? 0,
|
||||
redeemable: (p.redeemable as boolean) ?? false,
|
||||
mergeable: (p.mergeable as boolean) ?? false,
|
||||
title: (p.title as string) ?? null,
|
||||
slug: (p.slug as string) ?? null,
|
||||
icon: (p.icon as string) ?? null,
|
||||
eventSlug: (p.eventSlug as string) ?? null,
|
||||
outcome: (p.outcome as string) ?? null,
|
||||
outcomeIndex: (p.outcomeIndex as number) ?? null,
|
||||
oppositeOutcome: (p.oppositeOutcome as string) ?? null,
|
||||
oppositeAsset: (p.oppositeAsset as string) ?? null,
|
||||
endDate: (p.endDate as string) ?? null,
|
||||
negativeRisk: (p.negativeRisk as boolean) ?? false,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
positions,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
positions: {
|
||||
type: 'array',
|
||||
description: 'Array of position objects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
proxyWallet: { type: 'string', description: 'Proxy wallet address' },
|
||||
asset: { type: 'string', description: 'Asset token ID' },
|
||||
conditionId: { type: 'string', description: 'Condition ID' },
|
||||
size: { type: 'number', description: 'Position size' },
|
||||
avgPrice: { type: 'number', description: 'Average price' },
|
||||
initialValue: { type: 'number', description: 'Initial value' },
|
||||
currentValue: { type: 'number', description: 'Current value' },
|
||||
cashPnl: { type: 'number', description: 'Cash profit/loss' },
|
||||
percentPnl: { type: 'number', description: 'Percent profit/loss' },
|
||||
totalBought: { type: 'number', description: 'Total bought' },
|
||||
realizedPnl: { type: 'number', description: 'Realized profit/loss' },
|
||||
percentRealizedPnl: { type: 'number', description: 'Percent realized profit/loss' },
|
||||
curPrice: { type: 'number', description: 'Current price' },
|
||||
redeemable: { type: 'boolean', description: 'Whether position is redeemable' },
|
||||
mergeable: { type: 'boolean', description: 'Whether position is mergeable' },
|
||||
title: { type: 'string', description: 'Market title' },
|
||||
slug: { type: 'string', description: 'Market slug' },
|
||||
icon: { type: 'string', description: 'Market icon URL' },
|
||||
eventSlug: { type: 'string', description: 'Event slug' },
|
||||
outcome: { type: 'string', description: 'Outcome name' },
|
||||
outcomeIndex: { type: 'number', description: 'Outcome index' },
|
||||
oppositeOutcome: { type: 'string', description: 'Opposite outcome name' },
|
||||
oppositeAsset: { type: 'string', description: 'Opposite asset token ID' },
|
||||
endDate: { type: 'string', description: 'End date' },
|
||||
negativeRisk: { type: 'boolean', description: 'Whether negative risk' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
import { buildClobUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetPriceParams {
|
||||
tokenId: string // The token ID (CLOB token ID from market)
|
||||
side: string // 'buy' or 'sell'
|
||||
}
|
||||
|
||||
export interface PolymarketGetPriceResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
price: string
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetPriceTool: ToolConfig<
|
||||
PolymarketGetPriceParams,
|
||||
PolymarketGetPriceResponse
|
||||
> = {
|
||||
id: 'polymarket_get_price',
|
||||
name: 'Get Price from Polymarket',
|
||||
description: 'Retrieve the market price for a specific token and side',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
tokenId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description:
|
||||
'The CLOB token ID from market clobTokenIds array (e.g., "71321045679252212594626385532706912750332728571942532289631379312455583992563").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
side: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Order side: "buy" or "sell".',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('token_id', params.tokenId)
|
||||
queryParams.append('side', params.side.toUpperCase())
|
||||
return `${buildClobUrl('/price')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_price')
|
||||
}
|
||||
|
||||
// API returns { price: 0.45 }
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
price: String(data.price ?? ''),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
price: {
|
||||
type: 'string',
|
||||
description: 'Market price',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
import type { PolymarketPriceHistoryEntry } from '@/tools/polymarket/types'
|
||||
import { buildClobUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetPriceHistoryParams {
|
||||
tokenId: string
|
||||
interval?: string
|
||||
fidelity?: number
|
||||
startTs?: number
|
||||
endTs?: number
|
||||
}
|
||||
|
||||
export interface PolymarketGetPriceHistoryResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
history: PolymarketPriceHistoryEntry[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetPriceHistoryTool: ToolConfig<
|
||||
PolymarketGetPriceHistoryParams,
|
||||
PolymarketGetPriceHistoryResponse
|
||||
> = {
|
||||
id: 'polymarket_get_price_history',
|
||||
name: 'Get Price History from Polymarket',
|
||||
description: 'Retrieve historical price data for a specific market token',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
tokenId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description:
|
||||
'The CLOB token ID from market clobTokenIds array (e.g., "71321045679252212594626385532706912750332728571942532289631379312455583992563").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
interval: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Duration ending at current time (1m, 1h, 6h, 1d, 1w, max). Mutually exclusive with startTs/endTs.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
fidelity: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'Data resolution in minutes (e.g., 60 for hourly)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
startTs: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'Start timestamp (Unix seconds UTC)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
endTs: {
|
||||
type: 'number',
|
||||
required: false,
|
||||
description: 'End timestamp (Unix seconds UTC)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('market', params.tokenId)
|
||||
if (params.interval) queryParams.append('interval', params.interval)
|
||||
if (params.fidelity != null && !Number.isNaN(params.fidelity))
|
||||
queryParams.append('fidelity', String(params.fidelity))
|
||||
if (params.startTs != null && !Number.isNaN(params.startTs))
|
||||
queryParams.append('startTs', String(params.startTs))
|
||||
if (params.endTs != null && !Number.isNaN(params.endTs))
|
||||
queryParams.append('endTs', String(params.endTs))
|
||||
return `${buildClobUrl('/prices-history')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_price_history')
|
||||
}
|
||||
|
||||
const history = data.history || (Array.isArray(data) ? data : [])
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
history,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
history: {
|
||||
type: 'array',
|
||||
description: 'Array of price history entries',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
t: { type: 'number', description: 'Unix timestamp' },
|
||||
p: { type: 'number', description: 'Price at timestamp' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import type { PolymarketPaginationParams, PolymarketSeries } from '@/tools/polymarket/types'
|
||||
import { buildGammaUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetSeriesParams extends PolymarketPaginationParams {}
|
||||
|
||||
export interface PolymarketGetSeriesResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
series: PolymarketSeries[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetSeriesTool: ToolConfig<
|
||||
PolymarketGetSeriesParams,
|
||||
PolymarketGetSeriesResponse
|
||||
> = {
|
||||
id: 'polymarket_get_series',
|
||||
name: 'Get Series from Polymarket',
|
||||
description: 'Retrieve series (related market groups) from Polymarket',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results per page (e.g., "25"). Max: 50.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
offset: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results to skip for pagination (e.g., "50").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
// Default limit to 50 to prevent browser crashes from large data sets
|
||||
queryParams.append('limit', params.limit || '50')
|
||||
if (params.offset) queryParams.append('offset', params.offset)
|
||||
|
||||
const query = queryParams.toString()
|
||||
const url = buildGammaUrl('/series')
|
||||
return `${url}?${query}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_series')
|
||||
}
|
||||
|
||||
// Response is an array of series - each series can contain thousands of nested events
|
||||
// Strip the events array to prevent browser crashes (use get_events to fetch events separately)
|
||||
const series = Array.isArray(data)
|
||||
? data.map((s: any) => ({
|
||||
id: s.id,
|
||||
ticker: s.ticker,
|
||||
slug: s.slug,
|
||||
title: s.title,
|
||||
seriesType: s.seriesType,
|
||||
recurrence: s.recurrence,
|
||||
image: s.image,
|
||||
icon: s.icon,
|
||||
active: s.active,
|
||||
closed: s.closed,
|
||||
archived: s.archived,
|
||||
featured: s.featured,
|
||||
restricted: s.restricted,
|
||||
createdAt: s.createdAt,
|
||||
updatedAt: s.updatedAt,
|
||||
volume: s.volume,
|
||||
liquidity: s.liquidity,
|
||||
commentCount: s.commentCount,
|
||||
eventCount: s.events?.length || 0, // Include count instead of full array
|
||||
}))
|
||||
: []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
series,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
series: {
|
||||
type: 'array',
|
||||
description: 'Array of series objects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Series ID' },
|
||||
ticker: { type: 'string', description: 'Series ticker' },
|
||||
slug: { type: 'string', description: 'Series slug' },
|
||||
title: { type: 'string', description: 'Series title' },
|
||||
seriesType: { type: 'string', description: 'Series type' },
|
||||
recurrence: { type: 'string', description: 'Recurrence pattern' },
|
||||
image: { type: 'string', description: 'Series image URL' },
|
||||
icon: { type: 'string', description: 'Series icon URL' },
|
||||
active: { type: 'boolean', description: 'Whether series is active' },
|
||||
closed: { type: 'boolean', description: 'Whether series is closed' },
|
||||
archived: { type: 'boolean', description: 'Whether series is archived' },
|
||||
featured: { type: 'boolean', description: 'Whether series is featured' },
|
||||
volume: { type: 'number', description: 'Total volume' },
|
||||
liquidity: { type: 'number', description: 'Total liquidity' },
|
||||
eventCount: { type: 'number', description: 'Number of events in series' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import type { PolymarketSeries } from '@/tools/polymarket/types'
|
||||
import { buildGammaUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetSeriesByIdParams {
|
||||
seriesId: string // Series ID (required)
|
||||
}
|
||||
|
||||
export interface PolymarketGetSeriesByIdResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
series: PolymarketSeries
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetSeriesByIdTool: ToolConfig<
|
||||
PolymarketGetSeriesByIdParams,
|
||||
PolymarketGetSeriesByIdResponse
|
||||
> = {
|
||||
id: 'polymarket_get_series_by_id',
|
||||
name: 'Get Series by ID from Polymarket',
|
||||
description: 'Retrieve a specific series (related market group) by ID from Polymarket',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
seriesId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'The numeric series ID (e.g., "12345").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => buildGammaUrl(`/series/${params.seriesId.trim()}`),
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_series_by_id')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
series: data,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
series: {
|
||||
type: 'object',
|
||||
description: 'Series object with details',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Series ID' },
|
||||
ticker: { type: 'string', description: 'Series ticker' },
|
||||
slug: { type: 'string', description: 'Series slug' },
|
||||
title: { type: 'string', description: 'Series title' },
|
||||
seriesType: { type: 'string', description: 'Series type' },
|
||||
recurrence: { type: 'string', description: 'Recurrence pattern' },
|
||||
image: { type: 'string', description: 'Series image URL' },
|
||||
icon: { type: 'string', description: 'Series icon URL' },
|
||||
active: { type: 'boolean', description: 'Whether series is active' },
|
||||
closed: { type: 'boolean', description: 'Whether series is closed' },
|
||||
archived: { type: 'boolean', description: 'Whether series is archived' },
|
||||
featured: { type: 'boolean', description: 'Whether series is featured' },
|
||||
volume: { type: 'number', description: 'Total volume' },
|
||||
liquidity: { type: 'number', description: 'Total liquidity' },
|
||||
commentCount: { type: 'number', description: 'Comment count' },
|
||||
eventCount: { type: 'number', description: 'Number of events in series' },
|
||||
events: { type: 'array', description: 'Array of events in this series' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import type { PolymarketSpread } from '@/tools/polymarket/types'
|
||||
import { buildClobUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetSpreadParams {
|
||||
tokenId: string // The token ID (CLOB token ID from market)
|
||||
}
|
||||
|
||||
export interface PolymarketGetSpreadResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
spread: PolymarketSpread
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetSpreadTool: ToolConfig<
|
||||
PolymarketGetSpreadParams,
|
||||
PolymarketGetSpreadResponse
|
||||
> = {
|
||||
id: 'polymarket_get_spread',
|
||||
name: 'Get Spread from Polymarket',
|
||||
description: 'Retrieve the bid-ask spread for a specific token',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
tokenId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description:
|
||||
'The CLOB token ID from market clobTokenIds array (e.g., "71321045679252212594626385532706912750332728571942532289631379312455583992563").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('token_id', params.tokenId)
|
||||
return `${buildClobUrl('/spread')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_spread')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
spread: {
|
||||
spread: data.spread ?? '',
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
spread: {
|
||||
type: 'object',
|
||||
description: 'Spread value between bid and ask',
|
||||
properties: {
|
||||
spread: { type: 'string', description: 'The spread value' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import type { PolymarketPaginationParams, PolymarketTag } from '@/tools/polymarket/types'
|
||||
import { buildGammaUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetTagsParams extends PolymarketPaginationParams {}
|
||||
|
||||
export interface PolymarketGetTagsResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
tags: PolymarketTag[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetTagsTool: ToolConfig<PolymarketGetTagsParams, PolymarketGetTagsResponse> =
|
||||
{
|
||||
id: 'polymarket_get_tags',
|
||||
name: 'Get Tags from Polymarket',
|
||||
description: 'Retrieve available tags for filtering markets from Polymarket',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results per page (e.g., "25"). Max: 50.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
offset: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results to skip for pagination (e.g., "50").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
// Default limit to 50 to prevent browser crashes from large data sets
|
||||
queryParams.append('limit', params.limit || '50')
|
||||
if (params.offset) queryParams.append('offset', params.offset)
|
||||
|
||||
const query = queryParams.toString()
|
||||
const url = buildGammaUrl('/tags')
|
||||
return `${url}?${query}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_tags')
|
||||
}
|
||||
|
||||
// Response is an array of tags
|
||||
const tags = Array.isArray(data) ? data : []
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
tags,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
tags: {
|
||||
type: 'array',
|
||||
description: 'Array of tag objects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string', description: 'Tag ID' },
|
||||
label: { type: 'string', description: 'Tag label' },
|
||||
slug: { type: 'string', description: 'Tag slug' },
|
||||
createdAt: { type: 'string', description: 'Creation timestamp' },
|
||||
updatedAt: { type: 'string', description: 'Last update timestamp' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { buildClobUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetTickSizeParams {
|
||||
tokenId: string // The token ID (CLOB token ID from market)
|
||||
}
|
||||
|
||||
export interface PolymarketGetTickSizeResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
tickSize: string
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetTickSizeTool: ToolConfig<
|
||||
PolymarketGetTickSizeParams,
|
||||
PolymarketGetTickSizeResponse
|
||||
> = {
|
||||
id: 'polymarket_get_tick_size',
|
||||
name: 'Get Tick Size from Polymarket',
|
||||
description: 'Retrieve the minimum tick size for a specific token',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
tokenId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description:
|
||||
'The CLOB token ID from market clobTokenIds array (e.g., "71321045679252212594626385532706912750332728571942532289631379312455583992563").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('token_id', params.tokenId)
|
||||
return `${buildClobUrl('/tick-size')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_tick_size')
|
||||
}
|
||||
|
||||
// API returns { minimum_tick_size: "0.01" }
|
||||
const tickSize =
|
||||
typeof data === 'string' ? data : data.minimum_tick_size || data.tick_size || ''
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
tickSize: String(tickSize),
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
tickSize: {
|
||||
type: 'string',
|
||||
description: 'Minimum tick size',
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
import type { PolymarketTrade } from '@/tools/polymarket/types'
|
||||
import { buildDataUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketGetTradesParams {
|
||||
user?: string
|
||||
market?: string
|
||||
eventId?: string
|
||||
side?: string
|
||||
takerOnly?: string
|
||||
filterType?: string
|
||||
filterAmount?: string
|
||||
limit?: string
|
||||
offset?: string
|
||||
}
|
||||
|
||||
export interface PolymarketGetTradesResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
trades: PolymarketTrade[]
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketGetTradesTool: ToolConfig<
|
||||
PolymarketGetTradesParams,
|
||||
PolymarketGetTradesResponse
|
||||
> = {
|
||||
id: 'polymarket_get_trades',
|
||||
name: 'Get Trades from Polymarket',
|
||||
description: 'Retrieve trade history from Polymarket',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
user: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'User wallet address to filter trades',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
market: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description:
|
||||
'Market/condition ID to filter trades (e.g., "0x1234...abcd"). Mutually exclusive with eventId.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
eventId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Event ID to filter trades (e.g., "12345"). Mutually exclusive with market.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
side: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Trade direction filter (BUY or SELL)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
takerOnly: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter for taker trades only (true/false, default: true)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
filterType: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter type (CASH or TOKENS) - requires filterAmount',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
filterAmount: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter amount threshold - requires filterType',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results per page (e.g., "50"). Default: 100, max: 10000.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
offset: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Number of results to skip for pagination (e.g., "100").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
if (params.user) queryParams.append('user', params.user)
|
||||
if (params.market) queryParams.append('market', params.market)
|
||||
if (params.eventId) queryParams.append('eventId', params.eventId)
|
||||
if (params.side) queryParams.append('side', params.side.toUpperCase())
|
||||
if (params.takerOnly) queryParams.append('takerOnly', params.takerOnly)
|
||||
if (params.filterType) queryParams.append('filterType', params.filterType.toUpperCase())
|
||||
if (params.filterAmount) queryParams.append('filterAmount', params.filterAmount)
|
||||
if (params.limit) queryParams.append('limit', params.limit)
|
||||
if (params.offset) queryParams.append('offset', params.offset)
|
||||
|
||||
const url = buildDataUrl('/trades')
|
||||
return `${url}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'get_trades')
|
||||
}
|
||||
|
||||
const rawTrades = Array.isArray(data) ? data : []
|
||||
const trades: PolymarketTrade[] = rawTrades.map((t: Record<string, unknown>) => ({
|
||||
proxyWallet: (t.proxyWallet as string) ?? null,
|
||||
side: (t.side as string) ?? '',
|
||||
asset: (t.asset as string) ?? '',
|
||||
conditionId: (t.conditionId as string) ?? '',
|
||||
size: (t.size as number) ?? 0,
|
||||
price: (t.price as number) ?? 0,
|
||||
timestamp: (t.timestamp as number) ?? 0,
|
||||
title: (t.title as string) ?? null,
|
||||
slug: (t.slug as string) ?? null,
|
||||
icon: (t.icon as string) ?? null,
|
||||
eventSlug: (t.eventSlug as string) ?? null,
|
||||
outcome: (t.outcome as string) ?? null,
|
||||
outcomeIndex: (t.outcomeIndex as number) ?? null,
|
||||
name: (t.name as string) ?? null,
|
||||
pseudonym: (t.pseudonym as string) ?? null,
|
||||
bio: (t.bio as string) ?? null,
|
||||
profileImage: (t.profileImage as string) ?? null,
|
||||
profileImageOptimized: (t.profileImageOptimized as string) ?? null,
|
||||
transactionHash: (t.transactionHash as string) ?? null,
|
||||
}))
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
trades,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
trades: {
|
||||
type: 'array',
|
||||
description: 'Array of trade objects',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
proxyWallet: { type: 'string', description: 'Proxy wallet address' },
|
||||
side: { type: 'string', description: 'Trade side (BUY or SELL)' },
|
||||
asset: { type: 'string', description: 'Asset token ID' },
|
||||
conditionId: { type: 'string', description: 'Condition ID' },
|
||||
size: { type: 'number', description: 'Trade size' },
|
||||
price: { type: 'number', description: 'Trade price' },
|
||||
timestamp: { type: 'number', description: 'Unix timestamp' },
|
||||
title: { type: 'string', description: 'Market title' },
|
||||
slug: { type: 'string', description: 'Market slug' },
|
||||
icon: { type: 'string', description: 'Market icon URL' },
|
||||
eventSlug: { type: 'string', description: 'Event slug' },
|
||||
outcome: { type: 'string', description: 'Outcome name' },
|
||||
outcomeIndex: { type: 'number', description: 'Outcome index' },
|
||||
name: { type: 'string', description: 'Trader name' },
|
||||
pseudonym: { type: 'string', description: 'Trader pseudonym' },
|
||||
bio: { type: 'string', description: 'Trader bio' },
|
||||
profileImage: { type: 'string', description: 'Profile image URL' },
|
||||
profileImageOptimized: { type: 'string', description: 'Optimized profile image URL' },
|
||||
transactionHash: { type: 'string', description: 'Transaction hash' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
export { polymarketGetActivityTool } from './get_activity'
|
||||
export { polymarketGetEventTool } from './get_event'
|
||||
export { polymarketGetEventsTool } from './get_events'
|
||||
export { polymarketGetHoldersTool } from './get_holders'
|
||||
export { polymarketGetLastTradePriceTool } from './get_last_trade_price'
|
||||
export { polymarketGetLeaderboardTool } from './get_leaderboard'
|
||||
export { polymarketGetMarketTool } from './get_market'
|
||||
export { polymarketGetMarketsTool } from './get_markets'
|
||||
export { polymarketGetMidpointTool } from './get_midpoint'
|
||||
export { polymarketGetOrderbookTool } from './get_orderbook'
|
||||
export { polymarketGetPositionsTool } from './get_positions'
|
||||
export { polymarketGetPriceTool } from './get_price'
|
||||
export { polymarketGetPriceHistoryTool } from './get_price_history'
|
||||
export { polymarketGetSeriesTool } from './get_series'
|
||||
export { polymarketGetSeriesByIdTool } from './get_series_by_id'
|
||||
export { polymarketGetSpreadTool } from './get_spread'
|
||||
export { polymarketGetTagsTool } from './get_tags'
|
||||
export { polymarketGetTickSizeTool } from './get_tick_size'
|
||||
export { polymarketGetTradesTool } from './get_trades'
|
||||
export { polymarketSearchTool } from './search'
|
||||
@@ -0,0 +1,175 @@
|
||||
import type { PolymarketSearchResult } from '@/tools/polymarket/types'
|
||||
import { buildGammaUrl, handlePolymarketError } from '@/tools/polymarket/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export interface PolymarketSearchParams {
|
||||
query: string
|
||||
limit?: string
|
||||
page?: string
|
||||
cache?: string
|
||||
eventsStatus?: string
|
||||
eventsTag?: string
|
||||
sort?: string
|
||||
ascending?: string
|
||||
searchTags?: string
|
||||
searchProfiles?: string
|
||||
recurrence?: string
|
||||
excludeTagId?: string
|
||||
keepClosedMarkets?: string
|
||||
}
|
||||
|
||||
export interface PolymarketSearchResponse {
|
||||
success: boolean
|
||||
output: {
|
||||
results: PolymarketSearchResult
|
||||
}
|
||||
}
|
||||
|
||||
export const polymarketSearchTool: ToolConfig<PolymarketSearchParams, PolymarketSearchResponse> = {
|
||||
id: 'polymarket_search',
|
||||
name: 'Search Polymarket',
|
||||
description: 'Search for markets, events, and profiles on Polymarket',
|
||||
version: '1.0.0',
|
||||
|
||||
params: {
|
||||
query: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
description: 'Search query term (e.g., "presidential election", "bitcoin price").',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
limit: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Maximum number of results per type (events, tags, profiles). Default: 50.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
page: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Page number for pagination (e.g., "2"). 1-indexed.',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
cache: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Enable caching (true/false)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
eventsStatus: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter events by status',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
eventsTag: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter by event tags (comma-separated)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
sort: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Sort field',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
ascending: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Sort direction (true for ascending, false for descending)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
searchTags: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Include tags in search results (true/false)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
searchProfiles: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Include profiles in search results (true/false)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
recurrence: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Filter by recurrence type',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
excludeTagId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Exclude events with these tag IDs (comma-separated)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
keepClosedMarkets: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
description: 'Include closed markets in results (0 or 1)',
|
||||
visibility: 'user-or-llm',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params) => {
|
||||
const queryParams = new URLSearchParams()
|
||||
queryParams.append('q', params.query)
|
||||
// /public-search caps results via limit_per_type; a plain `limit` is ignored
|
||||
queryParams.append('limit_per_type', params.limit || '50')
|
||||
if (params.page) queryParams.append('page', params.page)
|
||||
if (params.cache) queryParams.append('cache', params.cache)
|
||||
if (params.eventsStatus) queryParams.append('events_status', params.eventsStatus)
|
||||
if (params.eventsTag) queryParams.append('events_tag', params.eventsTag)
|
||||
if (params.sort) queryParams.append('sort', params.sort)
|
||||
if (params.ascending) queryParams.append('ascending', params.ascending)
|
||||
if (params.searchTags) queryParams.append('search_tags', params.searchTags)
|
||||
if (params.searchProfiles) queryParams.append('search_profiles', params.searchProfiles)
|
||||
if (params.recurrence) queryParams.append('recurrence', params.recurrence)
|
||||
if (params.excludeTagId) queryParams.append('exclude_tag_id', params.excludeTagId)
|
||||
if (params.keepClosedMarkets)
|
||||
queryParams.append('keep_closed_markets', params.keepClosedMarkets)
|
||||
|
||||
return `${buildGammaUrl('/public-search')}?${queryParams.toString()}`
|
||||
},
|
||||
method: 'GET',
|
||||
headers: () => ({
|
||||
'Content-Type': 'application/json',
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!response.ok) {
|
||||
handlePolymarketError(data, response.status, 'search')
|
||||
}
|
||||
|
||||
// /public-search returns events, tags, and profiles (markets are nested within events)
|
||||
const results: PolymarketSearchResult = {
|
||||
events: data.events ?? [],
|
||||
tags: data.tags ?? [],
|
||||
profiles: data.profiles ?? [],
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
results,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
results: {
|
||||
type: 'object',
|
||||
description: 'Search results containing events, tags, and profiles arrays',
|
||||
properties: {
|
||||
events: { type: 'array', description: 'Array of matching event objects (markets nested)' },
|
||||
tags: { type: 'array', description: 'Array of matching tag objects' },
|
||||
profiles: { type: 'array', description: 'Array of matching profile objects' },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
const POLYMARKET_GAMMA_URL = 'https://gamma-api.polymarket.com'
|
||||
export const POLYMARKET_CLOB_URL = 'https://clob.polymarket.com'
|
||||
export const POLYMARKET_DATA_URL = 'https://data-api.polymarket.com'
|
||||
|
||||
export function buildGammaUrl(path: string): string {
|
||||
return `${POLYMARKET_GAMMA_URL}${path}`
|
||||
}
|
||||
|
||||
export function buildClobUrl(path: string): string {
|
||||
return `${POLYMARKET_CLOB_URL}${path}`
|
||||
}
|
||||
|
||||
export function buildDataUrl(path: string): string {
|
||||
return `${POLYMARKET_DATA_URL}${path}`
|
||||
}
|
||||
|
||||
export interface PolymarketPaginationParams {
|
||||
limit?: string
|
||||
offset?: string
|
||||
}
|
||||
|
||||
interface PolymarketPagingInfo {
|
||||
limit: number
|
||||
offset: number
|
||||
count: number
|
||||
}
|
||||
|
||||
export interface PolymarketMarket {
|
||||
id: string
|
||||
question: string
|
||||
conditionId: string
|
||||
slug: string
|
||||
resolutionSource: string
|
||||
endDate: string
|
||||
liquidity: string
|
||||
startDate: string
|
||||
image: string
|
||||
icon: string
|
||||
description: string
|
||||
outcomes: string
|
||||
outcomePrices: string
|
||||
volume: string
|
||||
active: boolean
|
||||
closed: boolean
|
||||
marketMakerAddress: string
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
new: boolean
|
||||
featured: boolean
|
||||
submitted_by: string
|
||||
archived: boolean
|
||||
resolvedBy: string
|
||||
restricted: boolean
|
||||
groupItemTitle: string
|
||||
groupItemThreshold: string
|
||||
questionID: string
|
||||
enableOrderBook: boolean
|
||||
orderPriceMinTickSize: number
|
||||
orderMinSize: number
|
||||
volumeNum: number
|
||||
liquidityNum: number
|
||||
clobTokenIds: string[]
|
||||
acceptingOrders: boolean
|
||||
negRisk: boolean
|
||||
}
|
||||
|
||||
export interface PolymarketEvent {
|
||||
id: string
|
||||
ticker: string
|
||||
slug: string
|
||||
title: string
|
||||
description: string
|
||||
startDate: string
|
||||
creationDate: string
|
||||
endDate: string
|
||||
image: string
|
||||
icon: string
|
||||
active: boolean
|
||||
closed: boolean
|
||||
archived: boolean
|
||||
new: boolean
|
||||
featured: boolean
|
||||
restricted: boolean
|
||||
liquidity: number
|
||||
volume: number
|
||||
openInterest: number
|
||||
commentCount: number
|
||||
markets: PolymarketMarket[]
|
||||
}
|
||||
|
||||
export interface PolymarketTag {
|
||||
id: string
|
||||
label: string
|
||||
slug: string
|
||||
createdAt?: string
|
||||
updatedAt?: string
|
||||
forceShow?: boolean
|
||||
forceHide?: boolean
|
||||
isCarousel?: boolean
|
||||
}
|
||||
|
||||
interface PolymarketOrderBookEntry {
|
||||
price: string
|
||||
size: string
|
||||
}
|
||||
|
||||
export interface PolymarketOrderBook {
|
||||
market: string
|
||||
asset_id: string
|
||||
hash: string
|
||||
timestamp: string
|
||||
bids: PolymarketOrderBookEntry[]
|
||||
asks: PolymarketOrderBookEntry[]
|
||||
min_order_size: string
|
||||
tick_size: string
|
||||
neg_risk: boolean
|
||||
last_trade_price: string
|
||||
}
|
||||
|
||||
interface PolymarketPrice {
|
||||
price: string
|
||||
}
|
||||
|
||||
export interface PolymarketPriceHistoryEntry {
|
||||
t: number
|
||||
p: number
|
||||
}
|
||||
|
||||
export interface PolymarketSeries {
|
||||
id: string
|
||||
ticker: string
|
||||
slug: string
|
||||
title: string
|
||||
seriesType: string
|
||||
recurrence: string
|
||||
image: string
|
||||
icon: string
|
||||
active: boolean
|
||||
closed: boolean
|
||||
archived: boolean
|
||||
featured: boolean
|
||||
restricted: boolean
|
||||
createdAt: string
|
||||
updatedAt: string
|
||||
volume: number
|
||||
liquidity: number
|
||||
commentCount: number
|
||||
eventCount: number
|
||||
}
|
||||
|
||||
export interface PolymarketSearchResult {
|
||||
events: PolymarketEvent[]
|
||||
tags: PolymarketTag[]
|
||||
profiles: PolymarketProfile[]
|
||||
}
|
||||
|
||||
interface PolymarketProfile {
|
||||
id: string
|
||||
name: string | null
|
||||
pseudonym: string | null
|
||||
bio: string | null
|
||||
profileImage: string | null
|
||||
profileImageOptimized: string | null
|
||||
walletAddress: string
|
||||
}
|
||||
|
||||
export interface PolymarketSpread {
|
||||
spread: string
|
||||
}
|
||||
|
||||
export interface PolymarketPosition {
|
||||
proxyWallet: string | null
|
||||
asset: string
|
||||
conditionId: string
|
||||
size: number
|
||||
avgPrice: number
|
||||
initialValue: number
|
||||
currentValue: number
|
||||
cashPnl: number
|
||||
percentPnl: number
|
||||
totalBought: number
|
||||
realizedPnl: number
|
||||
percentRealizedPnl: number
|
||||
curPrice: number
|
||||
redeemable: boolean
|
||||
mergeable: boolean
|
||||
title: string | null
|
||||
slug: string | null
|
||||
icon: string | null
|
||||
eventSlug: string | null
|
||||
outcome: string | null
|
||||
outcomeIndex: number | null
|
||||
oppositeOutcome: string | null
|
||||
oppositeAsset: string | null
|
||||
endDate: string | null
|
||||
negativeRisk: boolean
|
||||
}
|
||||
|
||||
export interface PolymarketTrade {
|
||||
proxyWallet: string | null
|
||||
side: string
|
||||
asset: string
|
||||
conditionId: string
|
||||
size: number
|
||||
price: number
|
||||
timestamp: number
|
||||
title: string | null
|
||||
slug: string | null
|
||||
icon: string | null
|
||||
eventSlug: string | null
|
||||
outcome: string | null
|
||||
outcomeIndex: number | null
|
||||
name: string | null
|
||||
pseudonym: string | null
|
||||
bio: string | null
|
||||
profileImage: string | null
|
||||
profileImageOptimized: string | null
|
||||
transactionHash: string | null
|
||||
}
|
||||
|
||||
export interface PolymarketActivity {
|
||||
proxyWallet: string | null
|
||||
timestamp: number
|
||||
conditionId: string
|
||||
type: string
|
||||
size: number
|
||||
usdcSize: number
|
||||
transactionHash: string | null
|
||||
price: number | null
|
||||
asset: string | null
|
||||
side: string | null
|
||||
outcomeIndex: number | null
|
||||
title: string | null
|
||||
slug: string | null
|
||||
icon: string | null
|
||||
eventSlug: string | null
|
||||
outcome: string | null
|
||||
name: string | null
|
||||
pseudonym: string | null
|
||||
bio: string | null
|
||||
profileImage: string | null
|
||||
profileImageOptimized: string | null
|
||||
}
|
||||
|
||||
export interface PolymarketLeaderboardEntry {
|
||||
rank: string
|
||||
proxyWallet: string
|
||||
userName: string | null
|
||||
vol: number
|
||||
pnl: number
|
||||
profileImage: string | null
|
||||
xUsername: string | null
|
||||
verifiedBadge: boolean
|
||||
}
|
||||
|
||||
interface PolymarketHolder {
|
||||
proxyWallet: string
|
||||
bio: string | null
|
||||
asset: string
|
||||
pseudonym: string | null
|
||||
amount: number
|
||||
displayUsernamePublic: boolean
|
||||
outcomeIndex: number
|
||||
name: string | null
|
||||
profileImage: string | null
|
||||
profileImageOptimized: string | null
|
||||
verified: boolean
|
||||
}
|
||||
|
||||
export interface PolymarketMarketHolders {
|
||||
token: string
|
||||
holders: PolymarketHolder[]
|
||||
}
|
||||
|
||||
export function handlePolymarketError(data: any, status: number, operation: string): never {
|
||||
const errorMessage = data?.message || data?.error || `Unknown error during ${operation}`
|
||||
throw new Error(`Polymarket API error (${status}): ${errorMessage}`)
|
||||
}
|
||||
Reference in New Issue
Block a user