use evmlib::common::Amount;
const PRICING_DIVISOR: u128 = 6000;
const DIVISOR_SQUARED: u128 = PRICING_DIVISOR * PRICING_DIVISOR;
const PRICE_BASELINE_WEI: u128 = 3_906_250_000_000_000;
const PRICE_COEFFICIENT_WEI: u128 = 35_156_250_000_000_000;
#[must_use]
pub fn calculate_price(close_records_stored: usize) -> Amount {
let n = Amount::from(close_records_stored);
let n_squared = n.saturating_mul(n);
let quadratic_wei = n_squared.saturating_mul(Amount::from(PRICE_COEFFICIENT_WEI))
/ Amount::from(DIVISOR_SQUARED);
Amount::from(PRICE_BASELINE_WEI).saturating_add(quadratic_wei)
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
const WEI_PER_TOKEN: u128 = 1_000_000_000_000_000_000;
fn expected_price(n: u64) -> Amount {
let n_amt = Amount::from(n);
let quad =
n_amt * n_amt * Amount::from(PRICE_COEFFICIENT_WEI) / Amount::from(DIVISOR_SQUARED);
Amount::from(PRICE_BASELINE_WEI) + quad
}
#[test]
fn test_zero_records_gets_baseline() {
let price = calculate_price(0);
assert_eq!(price, Amount::from(PRICE_BASELINE_WEI));
}
#[test]
fn test_baseline_is_nonzero_spam_barrier() {
assert!(calculate_price(0) > Amount::ZERO);
assert!(calculate_price(1) > calculate_price(0));
}
#[test]
fn test_one_record_above_baseline() {
let price = calculate_price(1);
assert_eq!(price, expected_price(1));
assert!(price > Amount::from(PRICE_BASELINE_WEI));
}
#[test]
fn test_at_divisor_is_baseline_plus_k() {
let price = calculate_price(6000);
let expected = Amount::from(PRICE_BASELINE_WEI + PRICE_COEFFICIENT_WEI);
assert_eq!(price, expected);
}
#[test]
fn test_double_divisor_is_baseline_plus_four_k() {
let price = calculate_price(12000);
let expected = Amount::from(PRICE_BASELINE_WEI + 4 * PRICE_COEFFICIENT_WEI);
assert_eq!(price, expected);
}
#[test]
fn test_triple_divisor_is_baseline_plus_nine_k() {
let price = calculate_price(18000);
let expected = Amount::from(PRICE_BASELINE_WEI + 9 * PRICE_COEFFICIENT_WEI);
assert_eq!(price, expected);
}
#[test]
fn test_smooth_pricing_no_staircase() {
let price_6k = calculate_price(6000);
let price_11k = calculate_price(11999);
assert!(
price_11k > price_6k,
"11999 records ({price_11k}) should cost more than 6000 ({price_6k})"
);
}
#[test]
fn test_price_increases_with_records() {
let price_low = calculate_price(6000);
let price_mid = calculate_price(12000);
let price_high = calculate_price(18000);
assert!(price_mid > price_low);
assert!(price_high > price_mid);
}
#[test]
fn test_price_increases_monotonically() {
let mut prev_price = Amount::ZERO;
for records in (0..60000).step_by(100) {
let price = calculate_price(records);
assert!(
price >= prev_price,
"Price at {records} records ({price}) should be >= previous ({prev_price})"
);
prev_price = price;
}
}
#[test]
fn test_large_value_no_overflow() {
let price = calculate_price(usize::MAX);
assert!(price > Amount::ZERO);
}
#[test]
fn test_price_deterministic() {
let price1 = calculate_price(12000);
let price2 = calculate_price(12000);
assert_eq!(price1, price2);
}
#[test]
fn test_quadratic_growth_excluding_baseline() {
let base = Amount::from(PRICE_BASELINE_WEI);
let quad_6k = calculate_price(6000) - base;
let quad_12k = calculate_price(12000) - base;
let quad_24k = calculate_price(24000) - base;
assert_eq!(quad_12k, quad_6k * Amount::from(4u64));
assert_eq!(quad_24k, quad_6k * Amount::from(16u64));
}
#[test]
fn test_small_record_counts_near_baseline() {
let price = calculate_price(100);
assert_eq!(price, expected_price(100));
assert!(price < Amount::from(WEI_PER_TOKEN)); assert!(price > Amount::from(PRICE_BASELINE_WEI)); }
}