arbos/l1_pricing/
batch_poster.rs1use 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}