|
| 1 | +use starknet_api::block::GasPrice; |
| 2 | + |
| 3 | +use crate::snip35::{compute_fee_actual, compute_fee_proposal, compute_fee_target}; |
| 4 | + |
| 5 | +#[test] |
| 6 | +fn test_compute_fee_actual_with_10_identical_values() { |
| 7 | + let proposals: Vec<GasPrice> = vec![GasPrice(1000); 10]; |
| 8 | + assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(1000))); |
| 9 | +} |
| 10 | + |
| 11 | +#[test] |
| 12 | +fn test_compute_fee_actual_with_ascending_values() { |
| 13 | + let proposals: Vec<GasPrice> = (1..=10).map(|i| GasPrice(i * 100)).collect(); |
| 14 | + // Sorted: 100,200,300,400,500,600,700,800,900,1000. Median = (500+600)/2 = 550. |
| 15 | + assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(550))); |
| 16 | +} |
| 17 | + |
| 18 | +#[test] |
| 19 | +fn test_compute_fee_actual_with_descending_values() { |
| 20 | + let proposals: Vec<GasPrice> = (1..=10).rev().map(|i| GasPrice(i * 100)).collect(); |
| 21 | + // Same sorted order, same median. |
| 22 | + assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(550))); |
| 23 | +} |
| 24 | + |
| 25 | +#[test] |
| 26 | +fn test_compute_fee_actual_with_outliers() { |
| 27 | + let mut proposals: Vec<GasPrice> = vec![GasPrice(100); 8]; |
| 28 | + proposals.push(GasPrice(1)); // Low outlier |
| 29 | + proposals.push(GasPrice(1_000_000)); // High outlier |
| 30 | + // Sorted: 1,100,100,100,100,100,100,100,100,1000000. Median = (100+100)/2 = 100. |
| 31 | + assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(100))); |
| 32 | +} |
| 33 | + |
| 34 | +#[test] |
| 35 | +fn test_compute_fee_actual_fewer_than_window_returns_none() { |
| 36 | + let proposals: Vec<GasPrice> = vec![GasPrice(100); 9]; |
| 37 | + assert_eq!(compute_fee_actual(&proposals, 10), None); |
| 38 | +} |
| 39 | + |
| 40 | +#[test] |
| 41 | +fn test_compute_fee_actual_empty_returns_none() { |
| 42 | + assert_eq!(compute_fee_actual(&[], 10), None); |
| 43 | +} |
| 44 | + |
| 45 | +#[test] |
| 46 | +fn test_compute_fee_actual_custom_window_size() { |
| 47 | + let proposals: Vec<GasPrice> = vec![GasPrice(200); 4]; |
| 48 | + assert_eq!(compute_fee_actual(&proposals, 4), Some(GasPrice(200))); |
| 49 | + assert_eq!(compute_fee_actual(&proposals, 5), None); |
| 50 | +} |
| 51 | + |
| 52 | +#[test] |
| 53 | +fn test_compute_fee_actual_zero_median_returns_none() { |
| 54 | + // All zeros → median is 0 → returns None (triggers l2_gas_price fallback). |
| 55 | + let proposals: Vec<GasPrice> = vec![GasPrice(0); 10]; |
| 56 | + assert_eq!(compute_fee_actual(&proposals, 10), None); |
| 57 | +} |
| 58 | + |
| 59 | +#[test] |
| 60 | +fn test_compute_fee_actual_uses_only_last_window_entries() { |
| 61 | + // 12 entries: first 2 are outliers, last 10 are 500. |
| 62 | + let mut proposals: Vec<GasPrice> = vec![GasPrice(999_999); 2]; |
| 63 | + proposals.extend(vec![GasPrice(500); 10]); |
| 64 | + // With window_size=10, the outliers should be ignored (only last 10 used). |
| 65 | + assert_eq!(compute_fee_actual(&proposals, 10), Some(GasPrice(500))); |
| 66 | +} |
| 67 | + |
| 68 | +#[test] |
| 69 | +fn test_compute_fee_target_normal() { |
| 70 | + // Target: $3e-9/gas = 3_000_000_000 atto-USD. STRK at $0.50 = 500_000_000_000_000_000. |
| 71 | + // floor = 3_000_000_000 * 10^18 / 500_000_000_000_000_000 = 6_000_000_000. |
| 72 | + let target = compute_fee_target(3_000_000_000, 500_000_000_000_000_000, 0, u128::MAX); |
| 73 | + assert_eq!(target, GasPrice(6_000_000_000)); |
| 74 | +} |
| 75 | + |
| 76 | +#[test] |
| 77 | +fn test_compute_fee_target_clamp_min() { |
| 78 | + let target = compute_fee_target(1, 10u128.pow(18), 100, u128::MAX); |
| 79 | + // floor = 1 * 10^18 / 10^18 = 1, but clamped to min 100. |
| 80 | + assert_eq!(target, GasPrice(100)); |
| 81 | +} |
| 82 | + |
| 83 | +#[test] |
| 84 | +fn test_compute_fee_target_clamp_max() { |
| 85 | + // Very low STRK price → very high floor, clamped to max. |
| 86 | + let target = compute_fee_target(10u128.pow(18), 1, 0, 1000); |
| 87 | + assert_eq!(target, GasPrice(1000)); |
| 88 | +} |
| 89 | + |
| 90 | +#[test] |
| 91 | +fn test_compute_fee_target_zero_rate() { |
| 92 | + let target = compute_fee_target(100, 0, 0, 999); |
| 93 | + assert_eq!(target, GasPrice(999)); |
| 94 | +} |
| 95 | + |
| 96 | +#[test] |
| 97 | +fn test_compute_fee_proposal_oracle_failure_freezes() { |
| 98 | + let proposal = compute_fee_proposal(None, GasPrice(1000), 2); |
| 99 | + assert_eq!(proposal, GasPrice(1000)); |
| 100 | +} |
| 101 | + |
| 102 | +#[test] |
| 103 | +fn test_compute_fee_proposal_target_above_actual() { |
| 104 | + // fee_target=2000, fee_actual=1000, margin=2ppt. Upper bound = 1000*1002/1000 = 1002. |
| 105 | + let proposal = compute_fee_proposal(Some(GasPrice(2000)), GasPrice(1000), 2); |
| 106 | + assert_eq!(proposal, GasPrice(1002)); |
| 107 | +} |
| 108 | + |
| 109 | +#[test] |
| 110 | +fn test_compute_fee_proposal_target_below_actual() { |
| 111 | + // fee_target=500, fee_actual=1000, margin=2ppt. Lower bound = 1000*1000/1002 = 998. |
| 112 | + let proposal = compute_fee_proposal(Some(GasPrice(500)), GasPrice(1000), 2); |
| 113 | + assert_eq!(proposal, GasPrice(998)); |
| 114 | +} |
| 115 | + |
| 116 | +#[test] |
| 117 | +fn test_compute_fee_proposal_target_within_bounds() { |
| 118 | + // fee_target=1001, fee_actual=1000, margin=2ppt. 1001 is within [998, 1002]. |
| 119 | + let proposal = compute_fee_proposal(Some(GasPrice(1001)), GasPrice(1000), 2); |
| 120 | + assert_eq!(proposal, GasPrice(1001)); |
| 121 | +} |
| 122 | + |
| 123 | +#[test] |
| 124 | +fn test_compute_fee_proposal_fee_actual_zero_clamps_to_zero() { |
| 125 | + // When fee_actual=0, both bounds are 0, so fee_proposal is always 0. |
| 126 | + let proposal = compute_fee_proposal(Some(GasPrice(1000)), GasPrice(0), 2); |
| 127 | + assert_eq!(proposal, GasPrice(0)); |
| 128 | +} |
| 129 | + |
| 130 | +#[test] |
| 131 | +fn test_compute_fee_actual_window_size_below_minimum_returns_none() { |
| 132 | + let proposals: Vec<GasPrice> = vec![GasPrice(100); 10]; |
| 133 | + assert_eq!(compute_fee_actual(&proposals, 0), None); |
| 134 | + assert_eq!(compute_fee_actual(&proposals, 1), None); |
| 135 | +} |
| 136 | + |
| 137 | +#[test] |
| 138 | +fn test_compute_fee_proposal_custom_margin() { |
| 139 | + // margin=10ppt (1%). fee_actual=10000. Upper=10000*1010/1000=10100. Lower=10000*1000/1010=9900. |
| 140 | + let proposal_up = compute_fee_proposal(Some(GasPrice(99999)), GasPrice(10000), 10); |
| 141 | + assert_eq!(proposal_up, GasPrice(10100)); |
| 142 | + let proposal_down = compute_fee_proposal(Some(GasPrice(1)), GasPrice(10000), 10); |
| 143 | + assert_eq!(proposal_down, GasPrice(9900)); |
| 144 | +} |
0 commit comments