arbos/l1_pricing/
batch_poster.rs

1use alloy_primitives::{Address, U256};
2use revm::Database;
3
4use crate::address_set::AddressSet;
5use arb_storage::{Storage, StorageBackedAddress, StorageBackedBigInt};
6
7const BATCH_POSTER_TABLE_KEY: &[u8] = &[0];
8const POSTER_ADDRS_KEY: &[u8] = &[0];
9const POSTER_INFO_KEY: &[u8] = &[1];
10
11const TOTAL_FUNDS_DUE_OFFSET: u64 = 0;
12const FUNDS_DUE_OFFSET: u64 = 0;
13const PAY_TO_OFFSET: u64 = 1;
14
15pub struct BatchPostersTable<D> {
16    poster_addrs: AddressSet<D>,
17    poster_info: Storage<D>,
18    pub total_funds_due: StorageBackedBigInt<D>,
19}
20
21pub struct BatchPosterState<D> {
22    funds_due: StorageBackedBigInt<D>,
23    pay_to: StorageBackedAddress<D>,
24}
25
26pub struct FundsDueItem {
27    pub address: Address,
28    pub funds_due: U256,
29}
30
31pub fn initialize_batch_posters_table<D: Database>(
32    l1_pricing_storage: &Storage<D>,
33    initial_poster: Address,
34) {
35    let bpt_storage = l1_pricing_storage.open_sub_storage(BATCH_POSTER_TABLE_KEY);
36    let poster_addrs_storage = bpt_storage.open_sub_storage(POSTER_ADDRS_KEY);
37    let poster_info = bpt_storage.open_sub_storage(POSTER_INFO_KEY);
38
39    let addrs = crate::address_set::open_address_set(poster_addrs_storage);
40    let _ = addrs.add(initial_poster);
41
42    let bp_storage = poster_info.open_sub_storage(initial_poster.as_slice());
43    let pay_to =
44        StorageBackedAddress::new(bp_storage.state_ptr(), bp_storage.base_key(), PAY_TO_OFFSET);
45    let _ = pay_to.set(initial_poster);
46
47    let funds_due = StorageBackedBigInt::new(
48        bp_storage.state_ptr(),
49        bp_storage.base_key(),
50        FUNDS_DUE_OFFSET,
51    );
52    let _ = funds_due.set(U256::ZERO);
53
54    let total_funds_due = StorageBackedBigInt::new(
55        bpt_storage.state_ptr(),
56        bpt_storage.base_key(),
57        TOTAL_FUNDS_DUE_OFFSET,
58    );
59    let _ = total_funds_due.set(U256::ZERO);
60}
61
62pub fn open_batch_posters_table<D: Database>(
63    l1_pricing_storage: &Storage<D>,
64) -> BatchPostersTable<D> {
65    let bpt_storage = l1_pricing_storage.open_sub_storage(BATCH_POSTER_TABLE_KEY);
66    let poster_addrs_storage = bpt_storage.open_sub_storage(POSTER_ADDRS_KEY);
67    let poster_info = bpt_storage.open_sub_storage(POSTER_INFO_KEY);
68
69    let poster_addrs = crate::address_set::open_address_set(poster_addrs_storage);
70    let total_funds_due = StorageBackedBigInt::new(
71        bpt_storage.state_ptr(),
72        bpt_storage.base_key(),
73        TOTAL_FUNDS_DUE_OFFSET,
74    );
75
76    BatchPostersTable {
77        poster_addrs,
78        poster_info,
79        total_funds_due,
80    }
81}
82
83impl<D: Database> BatchPostersTable<D> {
84    pub fn open(l1_pricing_storage: &Storage<D>) -> Self {
85        open_batch_posters_table(l1_pricing_storage)
86    }
87
88    pub fn contains_poster(&self, poster: Address) -> Result<bool, ()> {
89        self.poster_addrs.is_member(poster)
90    }
91
92    pub fn open_poster(
93        &self,
94        poster: Address,
95        create_if_not_exist: bool,
96    ) -> Result<BatchPosterState<D>, ()> {
97        let is_poster = self.poster_addrs.is_member(poster)?;
98        if !is_poster {
99            if !create_if_not_exist {
100                return Err(());
101            }
102            return self.add_poster(poster, poster);
103        }
104        Ok(self.internal_open(poster))
105    }
106
107    pub fn add_poster(
108        &self,
109        poster_address: Address,
110        pay_to: Address,
111    ) -> Result<BatchPosterState<D>, ()> {
112        let is_poster = self.poster_addrs.is_member(poster_address)?;
113        if is_poster {
114            return Err(());
115        }
116
117        let bp_state = self.internal_open(poster_address);
118        bp_state.funds_due.set(U256::ZERO)?;
119        bp_state.pay_to.set(pay_to)?;
120        self.poster_addrs.add(poster_address)?;
121        Ok(bp_state)
122    }
123
124    fn internal_open(&self, poster: Address) -> BatchPosterState<D> {
125        let bp_storage = self.poster_info.open_sub_storage(poster.as_slice());
126        BatchPosterState {
127            funds_due: StorageBackedBigInt::new(
128                bp_storage.state_ptr(),
129                bp_storage.base_key(),
130                FUNDS_DUE_OFFSET,
131            ),
132            pay_to: StorageBackedAddress::new(
133                bp_storage.state_ptr(),
134                bp_storage.base_key(),
135                PAY_TO_OFFSET,
136            ),
137        }
138    }
139
140    pub fn all_posters(&self) -> Result<Vec<Address>, ()> {
141        self.poster_addrs.all_members(u64::MAX)
142    }
143
144    pub fn total_funds_due(&self) -> Result<U256, ()> {
145        self.total_funds_due.get_raw()
146    }
147
148    pub fn get_funds_due_list(&self) -> Result<Vec<FundsDueItem>, ()> {
149        let posters = self.all_posters()?;
150        let mut result = Vec::new();
151        for poster in posters {
152            let state = self.internal_open(poster);
153            let due = state.funds_due()?;
154            if due > U256::ZERO {
155                result.push(FundsDueItem {
156                    address: poster,
157                    funds_due: due,
158                });
159            }
160        }
161        Ok(result)
162    }
163}
164
165impl<D: Database> BatchPosterState<D> {
166    pub fn funds_due(&self) -> Result<U256, ()> {
167        self.funds_due.get_raw()
168    }
169
170    pub fn set_funds_due(
171        &self,
172        value: U256,
173        total_funds_due: &StorageBackedBigInt<D>,
174    ) -> Result<(), ()> {
175        let prev = self.funds_due.get_raw().unwrap_or(U256::ZERO);
176        let prev_total = total_funds_due.get_raw().unwrap_or(U256::ZERO);
177        let new_total = prev_total.saturating_add(value).saturating_sub(prev);
178        total_funds_due.set(new_total)?;
179        self.funds_due.set(value)
180    }
181
182    pub fn pay_to(&self) -> Result<Address, ()> {
183        self.pay_to.get()
184    }
185
186    pub fn set_pay_to(&self, addr: Address) -> Result<(), ()> {
187        self.pay_to.set(addr)
188    }
189}