Skip to content

Commit 0c94aa6

Browse files
Merge branch 'main' into feature/multi-issue-implementation
2 parents 1232f03 + a979702 commit 0c94aa6

File tree

5 files changed

+1282
-2234
lines changed

5 files changed

+1282
-2234
lines changed

contracts/utility_contracts/src/debt_fuzz_tests.rs

Lines changed: 40 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,10 @@ mod debt_fuzz_tests {
1717
let token_address = env
1818
.register_stellar_asset_contract_v2(token_admin.clone())
1919
.address();
20-
let token_admin_client =
21-
soroban_sdk::token::StellarAssetClient::new(&env, &token_address);
20+
let token_admin_client = soroban_sdk::token::StellarAssetClient::new(&env, &token_address);
2221

2322
let device_public_key = BytesN::from_array(&env, &[1u8; 32]);
24-
23+
2524
// Test PostPaid meter with extreme debt scenarios
2625
let meter_id = client.register_meter_with_mode(
2726
&user,
@@ -34,7 +33,7 @@ mod debt_fuzz_tests {
3433

3534
// Test 1: High rate, long duration, zero balance scenario
3635
client.top_up(&meter_id, &1000000); // Initial collateral
37-
36+
3837
// Pair meter for usage deduction
3938
let _challenge = client.initiate_pairing(&meter_id);
4039
let signature = BytesN::from_array(&env, &[2u8; 64]);
@@ -45,7 +44,7 @@ mod debt_fuzz_tests {
4544
meter_id,
4645
timestamp: env.ledger().timestamp(),
4746
watt_hours_consumed: 100_000_000_000i128, // 100 billion Wh
48-
units_consumed: 10_000_000i128, // 10 million units
47+
units_consumed: 10_000_000i128, // 10 million units
4948
signature: BytesN::from_array(&env, &[3u8; 64]),
5049
public_key: device_public_key.clone(),
5150
};
@@ -54,42 +53,48 @@ mod debt_fuzz_tests {
5453
client.deduct_units(&extreme_usage);
5554

5655
let meter = client.get_meter(&meter_id).unwrap();
57-
56+
5857
// Verify debt is non-negative (critical underflow protection)
5958
assert!(meter.debt >= 0, "Debt should never be negative");
60-
59+
6160
// Verify debt accumulated correctly
6261
assert!(meter.debt > 0, "Debt should be positive after usage");
6362

6463
// Test 2: Verify debt clears correctly on top-up
6564
let debt_to_clear = meter.debt;
6665
token_admin_client.mint(&user, &debt_to_clear);
67-
66+
6867
client.top_up(&meter_id, &debt_to_clear);
69-
68+
7069
let meter_after_settlement = client.get_meter(&meter_id).unwrap();
71-
70+
7271
// Debt should be fully cleared
73-
assert_eq!(meter_after_settlement.debt, 0, "Debt should be fully cleared after sufficient top-up");
74-
72+
assert_eq!(
73+
meter_after_settlement.debt, 0,
74+
"Debt should be fully cleared after sufficient top-up"
75+
);
76+
7577
// Collateral should be properly updated
76-
assert!(meter_after_settlement.collateral_limit >= 0, "Collateral limit should remain non-negative");
78+
assert!(
79+
meter_after_settlement.collateral_limit >= 0,
80+
"Collateral limit should remain non-negative"
81+
);
7782

7883
// Test 3: Test with maximum safe values to ensure no underflow
7984
let max_safe_usage = SignedUsageData {
8085
meter_id,
8186
timestamp: env.ledger().timestamp(),
8287
watt_hours_consumed: i128::MAX / 1_000_000, // Safe maximum
83-
units_consumed: i128::MAX / 1_000_000_000, // Safe maximum
88+
units_consumed: i128::MAX / 1_000_000_000, // Safe maximum
8489
signature: BytesN::from_array(&env, &[4u8; 64]),
8590
public_key: device_public_key.clone(),
8691
};
8792

8893
// Should handle maximum values without panicking
8994
client.deduct_units(&max_safe_usage);
90-
95+
9196
let max_meter = client.get_meter(&meter_id).unwrap();
92-
97+
9398
// All values should remain within valid i128 range
9499
assert!(max_meter.debt >= 0 && max_meter.debt <= i128::MAX);
95100
assert!(max_meter.collateral_limit >= 0 && max_meter.collateral_limit <= i128::MAX);
@@ -112,7 +117,7 @@ mod debt_fuzz_tests {
112117
.address();
113118

114119
let device_public_key = BytesN::from_array(&env, &[1u8; 32]);
115-
120+
116121
// Test PrePaid meter with zero balance
117122
let meter_id = client.register_meter_with_mode(
118123
&user,
@@ -142,13 +147,19 @@ mod debt_fuzz_tests {
142147
client.deduct_units(&zero_balance_usage);
143148

144149
let meter = client.get_meter(&meter_id).unwrap();
145-
150+
146151
// Balance should be negative or zero, but never cause underflow
147-
assert!(meter.balance <= 0, "Balance should be zero or negative with insufficient funds");
148-
152+
assert!(
153+
meter.balance <= 0,
154+
"Balance should be zero or negative with insufficient funds"
155+
);
156+
149157
// Meter should be inactive with negative balance
150-
assert!(!meter.is_active, "Meter should be inactive with negative balance");
151-
158+
assert!(
159+
!meter.is_active,
160+
"Meter should be inactive with negative balance"
161+
);
162+
152163
// Balance should be within valid i128 range
153164
assert!(meter.balance >= i128::MIN && meter.balance <= i128::MAX);
154165
}
@@ -171,8 +182,7 @@ mod debt_fuzz_tests {
171182
let token_address = env
172183
.register_stellar_asset_contract_v2(token_admin.clone())
173184
.address();
174-
let token_admin_client =
175-
soroban_sdk::token::StellarAssetClient::new(&env, &token_address);
185+
let token_admin_client = soroban_sdk::token::StellarAssetClient::new(&env, &token_address);
176186
token_admin_client.mint(&user, &1_000_000_000_000i128);
177187

178188
let device_public_key = BytesN::from_array(&env, &[1u8; 32]);
@@ -182,11 +192,8 @@ mod debt_fuzz_tests {
182192
client.top_up(&meter_id, &1_000_000_000_000i128);
183193

184194
// Test large (but valid) usage updates
185-
let extreme_values: [i128; 3] = [
186-
1_000_000_000i128,
187-
10_000_000_000i128,
188-
100_000_000_000i128,
189-
];
195+
let extreme_values: [i128; 3] =
196+
[1_000_000_000i128, 10_000_000_000i128, 100_000_000_000i128];
190197

191198
for &usage in extreme_values.iter() {
192199
client.update_usage(&meter_id, &usage);
@@ -201,13 +208,8 @@ mod debt_fuzz_tests {
201208

202209
#[test]
203210
fn test_precision_factor_extremes() {
204-
let extreme_precision_factors: [i128; 5] = [
205-
1,
206-
1000,
207-
1_000_000,
208-
1_000_000_000,
209-
i128::MAX / 1000,
210-
];
211+
let extreme_precision_factors: [i128; 5] =
212+
[1, 1000, 1_000_000, 1_000_000_000, i128::MAX / 1000];
211213

212214
let test_usage = 1_000_000_000i128;
213215

@@ -224,15 +226,7 @@ mod debt_fuzz_tests {
224226

225227
#[test]
226228
fn test_arithmetic_edge_cases() {
227-
let edge_cases: [i128; 7] = [
228-
i128::MAX,
229-
i128::MIN,
230-
i128::MAX - 1,
231-
i128::MIN + 1,
232-
0,
233-
-1,
234-
1,
235-
];
229+
let edge_cases: [i128; 7] = [i128::MAX, i128::MIN, i128::MAX - 1, i128::MIN + 1, 0, -1, 1];
236230

237231
for &value in edge_cases.iter() {
238232
let _a = value.saturating_add(1);
@@ -263,8 +257,7 @@ mod debt_fuzz_tests {
263257
let token_address = env
264258
.register_stellar_asset_contract_v2(token_admin.clone())
265259
.address();
266-
let token_admin_client =
267-
soroban_sdk::token::StellarAssetClient::new(&env, &token_address);
260+
let token_admin_client = soroban_sdk::token::StellarAssetClient::new(&env, &token_address);
268261
token_admin_client.mint(&user, &i128::MAX);
269262

270263
let device_public_key = BytesN::from_array(&env, &[1u8; 32]);

contracts/utility_contracts/src/gas_estimator.rs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use soroban_sdk::{Env, Address};
1+
use soroban_sdk::{Address, Env};
22

33
pub struct GasCostEstimator;
44

@@ -22,7 +22,7 @@ impl GasCostEstimator {
2222
meters_in_group: u32,
2323
) -> i128 {
2424
let mut monthly_cost = Self::REGISTER_METER; // One-time registration
25-
25+
2626
// Add recurring costs
2727
monthly_cost += (Self::CLAIM as u32 * Self::CLAIMS_PER_MONTH) as i128;
2828
monthly_cost += (Self::UPDATE_HEARTBEAT as u32 * Self::HEARTBEATS_PER_MONTH) as i128;
@@ -57,7 +57,8 @@ impl GasCostEstimator {
5757
0
5858
};
5959

60-
let individual_cost = Self::estimate_meter_monthly_cost(_env, false, 0) * individual_meters as i128;
60+
let individual_cost =
61+
Self::estimate_meter_monthly_cost(_env, false, 0) * individual_meters as i128;
6162

6263
group_cost + individual_cost
6364
}
@@ -68,11 +69,12 @@ impl GasCostEstimator {
6869
group_billing_enabled: bool,
6970
) -> LargeScaleCostEstimate {
7071
let percentage_group = if group_billing_enabled { 0.8 } else { 0.0 }; // 80% in groups if enabled
71-
let monthly_cost = Self::estimate_provider_monthly_cost(env, number_of_meters, percentage_group);
72-
72+
let monthly_cost =
73+
Self::estimate_provider_monthly_cost(env, number_of_meters, percentage_group);
74+
7375
let annual_cost = monthly_cost * 12;
7476
let cost_per_meter = monthly_cost / number_of_meters as i128;
75-
77+
7678
// Convert to XLM (1 XLM = 10,000,000 stroops)
7779
let monthly_xlm = monthly_cost / 10_000_000;
7880
let annual_xlm = annual_cost / 10_000_000;
@@ -128,7 +130,11 @@ impl LargeScaleCostEstimate {
128130
self.cost_per_meter_xlm,
129131
self.annual_cost_xlm,
130132
self.cost_per_meter_xlm,
131-
if self.group_billing_enabled { "Enabled" } else { "Disabled" }
133+
if self.group_billing_enabled {
134+
"Enabled"
135+
} else {
136+
"Disabled"
137+
}
132138
)
133139
}
134140
}

0 commit comments

Comments
 (0)