get_recent_sales
Retrieve recent stamp sales with enhanced transaction details to analyze market activity and track blockchain transactions.
Instructions
Retrieve recent stamp sales with enhanced transaction details (v2.3 feature)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| stamp_id | No | Filter by specific stamp ID | |
| 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 |
Implementation Reference
- src/tools/stamps.ts:449-525 (handler)The execute method in GetRecentSalesTool implements the core handler logic for the get_recent_sales tool, including parameter validation, API call to fetch sales data, response formatting, and error handling.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 validation rules for filters like stamp_id, dayRange, pagination, and sorting.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)Registration of GetRecentSalesTool class in the stampTools export object under the 'get_recent_sales' key for tool discovery and instantiation.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 createStampTools that instantiates GetRecentSalesTool with API client and registers it under 'get_recent_sales' for use in tool servers.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.getRecentSales method that performs the actual API request for recent sales data, with version fallback and error handling, called by the tool handler.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, }; } ); }