pulse_trader_trades
Retrieve recent trades for a wallet address, showing buys, sells, sizes, prices, and PnL to support copy-trading and due diligence.
Instructions
Get recent trades for a specific wallet address. See exactly what a trader has been doing in the last minutes/hours — every buy, sell, size, price, and PnL. Essential for copy-trading and due diligence.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| useToonFormat | No | Return data in compact toon format (default: true). Set to false for standard JSON. | |
| address | Yes | Ethereum wallet address (0x...) | |
| since | No | Time window: e.g. '10m' (minutes), '1h' (hours), '1d' (days) | 1h |
| limit | No | Number of trades to return | |
| coin | No | Filter by coin symbol (e.g. BTC, ETH, SOL). For builder dex: prefix:COIN (e.g. xyz:SILVER) |
Implementation Reference
- src/index.ts:506-523 (registration)Registration of the pulse_trader_trades tool on the MCP server. Gated by shouldRegister() so it's only available when an API key is present (not in the free tier set).
if (shouldRegister("pulse_trader_trades")) server.registerTool( "pulse_trader_trades", { description: "Get recent trades for a specific wallet address. See exactly what a trader has been doing in the last minutes/hours — every buy, sell, size, price, and PnL. Essential for copy-trading and due diligence.", inputSchema: { useToonFormat: useToonFormatSchema, address: ethAddressSchema, since: sinceSchema.default("1h"), limit: z.number().min(1).max(100).default(50).describe("Number of trades to return"), coin: z.string().optional().describe("Filter by coin symbol (e.g. BTC, ETH, SOL). For builder dex: prefix:COIN (e.g. xyz:SILVER)"), }, }, async ({ useToonFormat, address, since, limit, coin }) => { const params: Record<string, string> = { since, limit: String(limit) }; if (coin) params.coin = normalizeCoin(coin); return toolResult(await callAPI(useToonFormat, `/pulse/trader/${address}/trades`, params)); } ); - src/index.ts:518-522 (handler)Handler function for pulse_trader_trades. Takes address (wallet), since (time window), limit, and optional coin filter, builds query params, then calls the backend API at /pulse/trader/{address}/trades.
async ({ useToonFormat, address, since, limit, coin }) => { const params: Record<string, string> = { since, limit: String(limit) }; if (coin) params.coin = normalizeCoin(coin); return toolResult(await callAPI(useToonFormat, `/pulse/trader/${address}/trades`, params)); } - src/index.ts:510-517 (schema)Input schema for pulse_trader_trades: useToonFormat (boolean), address (Ethereum address regex), since (time window like '1h'), limit (1-100, default 50), and optional coin filter.
inputSchema: { useToonFormat: useToonFormatSchema, address: ethAddressSchema, since: sinceSchema.default("1h"), limit: z.number().min(1).max(100).default(50).describe("Number of trades to return"), coin: z.string().optional().describe("Filter by coin symbol (e.g. BTC, ETH, SOL). For builder dex: prefix:COIN (e.g. xyz:SILVER)"), }, }, - src/index.ts:94-166 (helper)The callAPI helper used by the tool handler to make HTTP requests to the Coinversa backend. Supports retries, timeouts, and error handling.
async function callAPI(useToon: boolean, path: string, params?: Record<string, string>): Promise<any> { const url = new URL(`${BASE}${path}`); if (params) { Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== "") { url.searchParams.set(key, value); } }); } let lastError: Error | null = null; for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) { try { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS); const headers: Record<string, string> = {}; if (API_KEY) headers["X-API-Key"] = API_KEY; const response = await fetch(url.toString(), { headers, signal: controller.signal, }); clearTimeout(timeout); if (response.status === 429) { // Rate limited — retry after delay if (attempt < MAX_RETRIES) { await new Promise((r) => setTimeout(r, RETRY_DELAY_MS * (attempt + 1))); continue; } throw new Error("Rate limit exceeded. Please wait a moment and try again."); } if (response.status === 404) { throw new Error("Not found. The requested resource does not exist — check the address or symbol."); } if (response.status === 401) { throw new Error("Invalid API key. Check your COINVERSAA_API_KEY environment variable."); } if (!response.ok) { const body = await response.json().catch(() => null); const msg = body?.error || response.statusText; throw new Error(`Request failed (${response.status}): ${msg}`); } const data = await response.json(); return useToon ? toonEncode(data) : data; } catch (err: any) { if (err.name === "AbortError") { lastError = new Error("Request timed out after 30 seconds. The server may be under heavy load — try again."); } else if (err.cause?.code === "ECONNREFUSED" || err.cause?.code === "ENOTFOUND") { lastError = new Error("Cannot connect to the Coinversa API. Check your COINVERSAA_API_URL setting and network connection."); } else { lastError = err; } // Retry on transient network errors if (attempt < MAX_RETRIES && (err.name === "AbortError" || err.cause?.code === "ECONNRESET")) { await new Promise((r) => setTimeout(r, RETRY_DELAY_MS * (attempt + 1))); continue; } throw lastError; } } throw lastError || new Error("Request failed after retries"); } - src/index.ts:84-91 (helper)NormalizeCoin helper used to format coin symbols (uppercasing coin name while preserving builder dex prefix case) for the API request parameters.
function normalizeCoin(raw: string): string { const idx = raw.indexOf(':'); if (idx !== -1) { // Builder dex format — keep prefix lowercase, uppercase the coin return raw.slice(0, idx).toLowerCase() + ':' + raw.slice(idx + 1).toUpperCase(); } return raw.toUpperCase(); }