get_recent_sales
Retrieve recent stamp sales from the Stampchain MCP Server with options to filter by stamp ID, date range, and enhanced transaction details for better analysis.
Instructions
Retrieve recent stamp sales with enhanced transaction details (v2.3 feature)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| dayRange | No | Number of days to look back for sales | |
| fullDetails | No | Enable enhanced transaction information | |
| page | No | Page number | |
| page_size | No | Items per page | |
| sort_order | No | Sort order by timestamp | DESC |
| stamp_id | No | Filter by specific stamp ID |
Implementation Reference
- src/tools/stamps.ts:449-525 (handler)The execute method of GetRecentSalesTool that implements the core logic for the 'get_recent_sales' tool. Validates input parameters, checks API feature availability, fetches recent sales data from StampchainClient, formats it into a human-readable text response with metadata, and handles various errors.public async execute(params: GetRecentSalesParams, context?: ToolContext): Promise<ToolResponse> { try { context?.logger?.info('Executing get_recent_sales tool', { params }); // Validate parameters const validatedParams = this.validateParams(params); // Use API client from context if available, otherwise use instance client const client = context?.apiClient || this.apiClient; // Check if v2.3 features are available const features = client.getFeatureAvailability(); if (!features.recentSales) { return textResponse( 'Recent sales data is not available in the current API version. Please upgrade to v2.3 or later.' ); } // Get recent sales data const salesData: RecentSalesResponse = await client.getRecentSales(validatedParams); if (!salesData.data || salesData.data.length === 0) { return textResponse('No recent sales found for the specified criteria'); } // Format the response const lines = [ `Recent Sales (${salesData.data.length} results, ${validatedParams.dayRange} days):`, ]; lines.push('---'); salesData.data.forEach((sale, index) => { lines.push(`${index + 1}. Stamp #${sale.stamp_id}`); lines.push(` Transaction: ${sale.tx_hash}`); lines.push(` Block: ${sale.block_index}`); lines.push(` Price: ${sale.price_btc} BTC`); if (sale.price_usd) { lines.push(` Price USD: $${sale.price_usd.toFixed(2)}`); } if (sale.buyer_address) { lines.push(` Buyer: ${sale.buyer_address}`); } if (sale.time_ago) { lines.push(` Time: ${sale.time_ago}`); } if (sale.dispenser_address) { lines.push(` Dispenser: ${sale.dispenser_address}`); } lines.push(''); }); // Add metadata lines.push('Metadata:'); lines.push(`- Day Range: ${salesData.metadata.dayRange} days`); lines.push(`- Last Updated: ${new Date(salesData.metadata.lastUpdated).toISOString()}`); lines.push(`- Total Results: ${salesData.metadata.total}`); lines.push(`- Last Block: ${salesData.last_block}`); return textResponse(lines.join('\n')); } catch (error) { context?.logger?.error('Error executing get_recent_sales tool', { error }); if (error instanceof ValidationError) { throw error; } if (error instanceof ToolExecutionError) { throw error; } // Pass through the original error message for API errors if (error instanceof Error) { throw new ToolExecutionError(error.message, this.name, error); } throw new ToolExecutionError('Failed to retrieve recent sales data', this.name, error); }
- src/schemas/stamps.ts:232-241 (schema)Zod schema definition for input parameters of the get_recent_sales tool, including optional filters like stamp_id, dayRange, pagination, and sort order.export const GetRecentSalesParamsSchema = z.object({ stamp_id: z.number().int().positive().optional(), dayRange: z.number().int().min(1).max(365).optional().default(30), fullDetails: z.boolean().optional().default(false), page: z.number().int().min(1).optional().default(1), page_size: z.number().int().min(1).max(100).optional().default(20), sort_order: z.enum(['ASC', 'DESC']).optional().default('DESC'), }); export type GetRecentSalesParams = z.infer<typeof GetRecentSalesParamsSchema>;
- src/tools/stamps.ts:816-823 (registration)Object exporting the GetRecentSalesTool class constructor for registration in the stamp tools collection.export const stampTools = { get_stamp: GetStampTool, search_stamps: SearchStampsTool, get_recent_stamps: GetRecentStampsTool, get_recent_sales: GetRecentSalesTool, get_market_data: GetMarketDataTool, get_stamp_market_data: GetStampMarketDataTool, };
- src/tools/stamps.ts:828-837 (registration)Factory function that instantiates and returns GetRecentSalesTool along with other stamp tools, using a shared StampchainClient.export function createStampTools(apiClient?: StampchainClient) { return { get_stamp: new GetStampTool(apiClient), search_stamps: new SearchStampsTool(apiClient), get_recent_stamps: new GetRecentStampsTool(apiClient), get_recent_sales: new GetRecentSalesTool(apiClient), get_market_data: new GetMarketDataTool(apiClient), get_stamp_market_data: new GetStampMarketDataTool(apiClient), }; }
- src/api/stampchain-client.ts:368-426 (helper)StampchainClient method called by the tool handler to fetch recent sales data from the API, with version-aware fallbacks for older API versions.async getRecentSales(params: RecentSalesQueryParams = {}): Promise<RecentSalesResponse> { const features = this.getFeatureAvailability(); if (!features.recentSales) { // Fallback for older API versions - use regular stamps endpoint this.logger.info('Recent sales not available in this API version, using fallback'); const stamps = await this.searchStamps({ limit: params.page_size || 20, sort_order: params.sort_order || 'DESC', }); // Transform to match RecentSalesResponse format return { data: stamps.map((stamp) => ({ tx_hash: stamp.tx_hash, block_index: stamp.block_index, stamp_id: stamp.stamp || 0, price_btc: typeof stamp.floorPrice === 'number' ? stamp.floorPrice : 0, price_usd: stamp.floorPriceUSD || null, timestamp: stamp.block_index, // Use block_index as timestamp approximation })), metadata: { dayRange: params.dayRange || 30, lastUpdated: Date.now(), total: stamps.length, }, last_block: stamps[0]?.block_index || 0, }; } return this.executeWithFallback( () => this.client.get<RecentSalesResponse>('/stamps/recentSales', { params }).then((r) => r.data), async () => { // Fallback implementation for when v2.3 endpoint fails const stamps = await this.searchStamps({ limit: params.page_size || 20, sort_order: params.sort_order || 'DESC', }); return { data: stamps.map((stamp) => ({ tx_hash: stamp.tx_hash, block_index: stamp.block_index, stamp_id: stamp.stamp || 0, price_btc: typeof stamp.floorPrice === 'number' ? stamp.floorPrice : 0, price_usd: stamp.floorPriceUSD || null, timestamp: stamp.block_index, })), metadata: { dayRange: params.dayRange || 30, lastUpdated: Date.now(), total: stamps.length, }, last_block: stamps[0]?.block_index || 0, }; } ); }