arbos/programs/
data_pricer.rs

1use 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
14/// The day it all began (Arbitrum genesis timestamp).
15pub const ARBITRUM_START_TIME: u64 = 1421388000;
16
17const INITIAL_DEMAND: u32 = 0;
18/// 1TB total footprint per year, refilled each second.
19pub 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; // 5Mb = $1
23const INITIAL_INERTIA: u32 = 21360419; // expensive at 1Tb
24
25/// Stylus data pricing model using exponential demand curve.
26pub 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    /// Update the pricing model with new data usage and return cost in wei.
62    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
93/// Multiply a u64 by a bips value, saturating on overflow.
94fn 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}