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
| 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, }; } ); }