@@ -357,3 +357,166 @@ pub fn analytics_query(env: &Env, window: TimeWindow) -> AnalyticsResult {
357357 let unique_addresses = load_unique_count ( env) ;
358358 AnalyticsResult { all_time, window : wm, unique_addresses }
359359}
360+
361+ // ---------------------------------------------------------------------------
362+ // Issue #229 — named query functions
363+ // ---------------------------------------------------------------------------
364+
365+ /// Volume statistics: total trades created, total value locked, and per-window
366+ /// volume for the requested time window.
367+ ///
368+ /// Maps to the issue's `get_volume_stats()` requirement.
369+ pub fn get_volume_stats ( env : & Env , window : TimeWindow ) -> VolumeStats {
370+ let m = load_metrics ( env) ;
371+ let wm = load_or_reset_window ( env, & window) ;
372+ VolumeStats {
373+ trades_created : m. trades_created ,
374+ total_value : m. total_volume ,
375+ window_volume : wm. volume ,
376+ window_trades : wm. trades_created ,
377+ }
378+ }
379+
380+ /// Success-rate breakdown: completed / disputed / cancelled counts and the
381+ /// derived rate in basis points.
382+ ///
383+ /// Maps to the issue's `get_success_rate()` requirement.
384+ pub fn get_success_rate ( env : & Env ) -> SuccessRateStats {
385+ let m = load_metrics ( env) ;
386+ let terminal = m. trades_completed
387+ . saturating_add ( m. trades_cancelled )
388+ . saturating_add ( m. trades_disputed ) ;
389+ let success_rate_bps = if terminal == 0 {
390+ 0u32
391+ } else {
392+ ( ( m. trades_completed as u128 * 10_000 ) / terminal as u128 ) as u32
393+ } ;
394+ SuccessRateStats {
395+ completed : m. trades_completed ,
396+ disputed : m. trades_disputed ,
397+ cancelled : m. trades_cancelled ,
398+ success_rate_bps,
399+ }
400+ }
401+
402+ /// Platform usage metrics: active escrows, unique participants, fees collected.
403+ ///
404+ /// Maps to the issue's `get_platform_metrics()` requirement.
405+ /// (The existing `get_metrics` / `get_stats` remain unchanged; this adds the
406+ /// named shape the issue specifies.)
407+ pub fn get_platform_usage ( env : & Env ) -> PlatformUsage {
408+ let m = load_metrics ( env) ;
409+ let active_trades = m. trades_created
410+ . saturating_sub ( m. trades_completed )
411+ . saturating_sub ( m. trades_cancelled )
412+ . saturating_sub ( m. trades_disputed ) ;
413+ PlatformUsage {
414+ active_escrows : active_trades,
415+ unique_participants : load_unique_count ( env) ,
416+ total_fees_collected : m. total_fees_collected ,
417+ }
418+ }
419+
420+ /// All metrics scoped to an arbitrary `[start_time, end_time]` range
421+ /// (ledger UTC timestamps in seconds).
422+ ///
423+ /// Because Soroban storage cannot be iterated, this function compares the
424+ /// requested range against the stored rolling windows and returns the
425+ /// tightest-fitting window whose `window_start` falls within the range.
426+ /// For ranges that don't align with a preset window the all-time snapshot
427+ /// is returned with `window_matched` set to `false`.
428+ ///
429+ /// Maps to the issue's `get_analytics_by_period(start, end)` requirement.
430+ pub fn get_analytics_by_period ( env : & Env , start_time : u64 , end_time : u64 ) -> PeriodAnalytics {
431+ let now = env. ledger ( ) . timestamp ( ) ;
432+ let span = end_time. saturating_sub ( start_time) ;
433+
434+ // Pick the smallest preset window that fully covers the requested span.
435+ let window = if span <= 86_400 {
436+ TimeWindow :: Last24h
437+ } else if span <= 604_800 {
438+ TimeWindow :: Last7d
439+ } else if span <= 2_592_000 {
440+ TimeWindow :: Last30d
441+ } else {
442+ TimeWindow :: AllTime
443+ } ;
444+
445+ let wm = load_or_reset_window ( env, & window) ;
446+ // Report whether the stored window actually overlaps the requested range.
447+ let window_matched = wm. window_start >= start_time && wm. window_start <= end_time. min ( now) ;
448+
449+ let m = load_metrics ( env) ;
450+ let stats = compute_stats ( m) ;
451+
452+ PeriodAnalytics {
453+ start_time,
454+ end_time,
455+ window_matched,
456+ volume : wm. volume ,
457+ trades_created : wm. trades_created ,
458+ trades_completed : wm. trades_completed ,
459+ trades_disputed : wm. trades_disputed ,
460+ trades_cancelled : wm. trades_cancelled ,
461+ success_rate_bps : stats. success_rate_bps ,
462+ active_escrows : stats. active_trades ,
463+ unique_participants : load_unique_count ( env) ,
464+ total_fees_collected : stats. metrics . total_fees_collected ,
465+ }
466+ }
467+
468+ // ---------------------------------------------------------------------------
469+ // New return types for the named query functions
470+ // ---------------------------------------------------------------------------
471+
472+ /// Returned by `get_volume_stats`.
473+ #[ contracttype]
474+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
475+ pub struct VolumeStats {
476+ pub trades_created : u64 ,
477+ /// All-time cumulative value (stroops).
478+ pub total_value : u64 ,
479+ /// Volume within the requested time window (stroops).
480+ pub window_volume : u64 ,
481+ /// Trades created within the requested time window.
482+ pub window_trades : u64 ,
483+ }
484+
485+ /// Returned by `get_success_rate`.
486+ #[ contracttype]
487+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
488+ pub struct SuccessRateStats {
489+ pub completed : u64 ,
490+ pub disputed : u64 ,
491+ pub cancelled : u64 ,
492+ /// completed / (completed + disputed + cancelled) * 10_000.
493+ pub success_rate_bps : u32 ,
494+ }
495+
496+ /// Returned by `get_platform_usage`.
497+ #[ contracttype]
498+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
499+ pub struct PlatformUsage {
500+ pub active_escrows : u64 ,
501+ pub unique_participants : u64 ,
502+ pub total_fees_collected : u64 ,
503+ }
504+
505+ /// Returned by `get_analytics_by_period`.
506+ #[ contracttype]
507+ #[ derive( Clone , Debug , Eq , PartialEq ) ]
508+ pub struct PeriodAnalytics {
509+ pub start_time : u64 ,
510+ pub end_time : u64 ,
511+ /// `true` when a stored window overlaps the requested range.
512+ pub window_matched : bool ,
513+ pub volume : u64 ,
514+ pub trades_created : u64 ,
515+ pub trades_completed : u64 ,
516+ pub trades_disputed : u64 ,
517+ pub trades_cancelled : u64 ,
518+ pub success_rate_bps : u32 ,
519+ pub active_escrows : u64 ,
520+ pub unique_participants : u64 ,
521+ pub total_fees_collected : u64 ,
522+ }
0 commit comments