arbos/programs/
data_pricer.rs1use alloy_primitives::U256;
2use arb_math::ONE_IN_BIPS;
3use arb_storage::{Storage, StorageBackedUint32, StorageBackedUint64, StorageBackend};
4use revm::Database;
5
6use super::ProgramsError;
7
8const DEMAND_OFFSET: u64 = 0;
9const BYTES_PER_SECOND_OFFSET: u64 = 1;
10const LAST_UPDATE_TIME_OFFSET: u64 = 2;
11const MIN_PRICE_OFFSET: u64 = 3;
12const INERTIA_OFFSET: u64 = 4;
13
14pub const ARBITRUM_START_TIME: u64 = 1421388000;
16
17const INITIAL_DEMAND: u32 = 0;
18pub const INITIAL_HOURLY_BYTES: u64 = (1u64 << 40) / (365 * 24);
20const INITIAL_BYTES_PER_SECOND: u32 = (INITIAL_HOURLY_BYTES / (60 * 60)) as u32;
21const INITIAL_LAST_UPDATE_TIME: u64 = ARBITRUM_START_TIME;
22const INITIAL_MIN_PRICE: u32 = 82928201; const INITIAL_INERTIA: u32 = 21360419; pub struct DataPricer {
27 pub demand: StorageBackedUint32,
28 pub bytes_per_second: StorageBackedUint32,
29 pub last_update_time: StorageBackedUint64,
30 pub min_price: StorageBackedUint32,
31 pub inertia: StorageBackedUint32,
32}
33
34pub fn init_data_pricer<D: Database, B: StorageBackend>(
35 sto: &Storage<'_, D>,
36 backend: &mut B,
37) -> Result<(), ProgramsError> {
38 let base_key = sto.base_key();
39 StorageBackedUint32::new(base_key, DEMAND_OFFSET).set(backend, INITIAL_DEMAND)?;
40 StorageBackedUint32::new(base_key, BYTES_PER_SECOND_OFFSET)
41 .set(backend, INITIAL_BYTES_PER_SECOND)?;
42 StorageBackedUint64::new(base_key, LAST_UPDATE_TIME_OFFSET)
43 .set(backend, INITIAL_LAST_UPDATE_TIME)?;
44 StorageBackedUint32::new(base_key, MIN_PRICE_OFFSET).set(backend, INITIAL_MIN_PRICE)?;
45 StorageBackedUint32::new(base_key, INERTIA_OFFSET).set(backend, INITIAL_INERTIA)?;
46 Ok(())
47}
48
49pub fn open_data_pricer<D>(sto: &Storage<'_, D>) -> DataPricer {
50 let base_key = sto.base_key();
51 DataPricer {
52 demand: StorageBackedUint32::new(base_key, DEMAND_OFFSET),
53 bytes_per_second: StorageBackedUint32::new(base_key, BYTES_PER_SECOND_OFFSET),
54 last_update_time: StorageBackedUint64::new(base_key, LAST_UPDATE_TIME_OFFSET),
55 min_price: StorageBackedUint32::new(base_key, MIN_PRICE_OFFSET),
56 inertia: StorageBackedUint32::new(base_key, INERTIA_OFFSET),
57 }
58}
59
60impl DataPricer {
61 pub fn update_model<B: StorageBackend>(
63 &self,
64 backend: &mut B,
65 temp_bytes: u32,
66 time: u64,
67 ) -> Result<U256, ProgramsError> {
68 let demand = self.demand.get(backend).unwrap_or(0);
69 let bytes_per_second = self.bytes_per_second.get(backend).unwrap_or(0);
70 let last_update_time = self.last_update_time.get(backend).unwrap_or(0);
71 let min_price = self.min_price.get(backend).unwrap_or(0);
72 let inertia = self.inertia.get(backend)?;
73
74 if inertia == 0 {
75 return Ok(U256::ZERO);
76 }
77
78 let passed = (time.saturating_sub(last_update_time)) as u32;
79 let credit = bytes_per_second.saturating_mul(passed);
80 let demand = demand.saturating_sub(credit).saturating_add(temp_bytes);
81
82 self.demand.set(backend, demand)?;
83 self.last_update_time.set(backend, time)?;
84
85 let exponent = ONE_IN_BIPS * (demand as u64) / (inertia as u64);
86 let multiplier = arb_math::approx_exp_basis_points(exponent, 12);
87 let cost_per_byte = saturating_mul_by_bips(min_price as u64, multiplier);
88 let cost_in_wei = cost_per_byte.saturating_mul(temp_bytes as u64);
89 Ok(U256::from(cost_in_wei))
90 }
91}
92
93fn saturating_mul_by_bips(value: u64, bips: u64) -> u64 {
95 (value as u128 * bips as u128 / ONE_IN_BIPS as u128).min(u64::MAX as u128) as u64
96}