| Crates.io | rialo-aggregators-utils |
| lib.rs | rialo-aggregators-utils |
| version | 0.1.10 |
| created_at | 2025-12-09 14:28:15.849083+00 |
| updated_at | 2025-12-09 21:52:26.317205+00 |
| description | Rialo Aggregators Utils |
| homepage | |
| repository | |
| max_upload_size | |
| id | 1975567 |
| size | 74,717 |
This crate provides essential utilities for building robust aggregator programs in the Rialo ecosystem. It offers statistical functions, data processing tools, and error handling utilities to simplify the implementation of aggregator programs that process oracle data.
Rialo Aggregator Utils serves as a foundation library for developers building aggregator programs. It focuses on providing robust statistical methods and data extraction utilities that handle real-world challenges like outliers, malformed data, and varying data formats from multiple oracle sources.
Note the current implementation is focused on median calculation, with plans to extend to other statistical methods in the future. For future extensions ideas, please refer to the Future Extensions section.
The primary utility is a sophisticated median calculation system designed for processing oracle price data:
Comprehensive error handling for common oracle data issues:
Defines how to calculate the median when dealing with an even number of values:
pub enum MedianMethod {
/// Average the two middle values: (a + b) / 2 (default)
Average,
/// Take the lower of the two middle values
Lower,
/// Take the upper of the two middle values
Upper,
}
The core result structure that implements the RialoEvent trait:
#[derive(Clone, Debug, Default, PartialEq, RialoEvent)]
pub struct Median {
pub median: f64,
pub sample_size: usize,
}
Comprehensive result type that includes both the calculated median and any errors encountered:
pub struct MedianResult {
pub median: Median,
pub errors: Vec<(usize, ValueExtractionError)>,
}
use rialo_aggregator_utils::median::{Median, MedianMethod};
use rialo_oracle_processor_interface::state::OracleUpdate;
// Calculate median with default method (Average)
let result = Median::from_with_method("price", &oracle_updates, MedianMethod::Average);
// Access the median value
let median = result.median;
println!("Median price: {}, Sample size: {}", median.median, median.sample_size);
// Check for errors during processing
for (index, error) in result.errors() {
println!("Error at index {}: {}", index, error);
}
// For even-sized datasets, different methods yield different results
let updates = vec![/* oracle updates with values [10, 20, 30, 40] */];
// Average method: (20 + 30) / 2 = 25.0
let avg_result = Median::from_with_method("price", &updates, MedianMethod::Average);
// Lower method: 20.0
let lower_result = Median::from_with_method("price", &updates, MedianMethod::Lower);
// Upper method: 30.0
let upper_result = Median::from_with_method("price", &updates, MedianMethod::Upper);
// Process oracle updates with potential errors
let result = Median::from_with_method("price", &oracle_updates, MedianMethod::Average);
// The median is calculated from valid values only
println!("Calculated median: {}", result.median.median);
// Inspect any errors that occurred
match result.errors().len() {
0 => println!("All oracle updates processed successfully"),
n => {
println!("Encountered {} errors during processing:", n);
for (index, error) in result.errors() {
match error {
ValueExtractionError::DecodeError(_) => {
println!(" Oracle {} had invalid Base64 data", index);
}
ValueExtractionError::JsonError(_) => {
println!(" Oracle {} had malformed JSON", index);
}
ValueExtractionError::MissingKey(key) => {
println!(" Oracle {} missing key: {}", index, key);
}
ValueExtractionError::NotANumber(val) => {
println!(" Oracle {} had non-numeric value: {}", index, val);
}
}
}
}
}
The crate provides convenient From trait implementations for simple usage:
// Direct conversion for simple cases
let median: Median = ("price", &oracle_updates).into();
// Or get the full result with error information
let result: MedianResult = ("price", &oracle_updates).into();
The median calculation follows this robust pipeline:
The utility expects oracle updates with Base64-encoded JSON data:
{
"price": 50000.0,
"timestamp": 1634567890,
"source": "exchange_a"
}
The extract_value function handles:
Comprehensive error types for different failure modes:
pub enum ValueExtractionError {
/// Base64 decoding failed
DecodeError(DecodeError),
/// JSON parsing failed
JsonError(serde_json::Error),
/// Required key missing from JSON
MissingKey(String),
/// Value exists but is not numeric
NotANumber(String),
}
Each error provides detailed context for debugging and monitoring oracle data quality.
The Median struct implements RialoEvent, enabling direct emission:
// Calculate median and emit as event
let result = Median::from_with_method("price", &updates, MedianMethod::Average);
result.median.emit(program_id, &accounts)?;
Perfect for use in aggregator programs:
// In your aggregator program
let oracle_report_data = deserialize_oracle_report(&oracle_account)?;
let median_result = Median::from_with_method(
"price",
&oracle_report_data.into_updates(),
MedianMethod::Average
);
// Use the median in your business logic
let trading_pairs = TradingPairs::from_median_results(median_result);
This crate is designed to be extensible with additional utilities:
The crate includes comprehensive tests covering:
base64: Base64 encoding/decoding for oracle datarialo_events_core: Core event framework and derive macrosrialo_oracle_processor_interface: Oracle update data structuresserde_json: JSON parsing and manipulationthiserror: Error handling and derivationCopyright (c) Subzero Labs, Inc.
SPDX-License-Identifier: Apache-2.0