1use std::sync::Arc;
2
3use alloy_evm::precompiles::{DynPrecompile, PrecompileInput};
4use alloy_primitives::{Address, U256};
5use alloy_sol_types::SolInterface;
6use arb_context::ArbPrecompileCtx;
7use arb_storage::ARBOS_STATE_ADDRESS;
8use arbos::address_set::AddressSetError;
9use revm::precompile::{PrecompileId, PrecompileOutput, PrecompileResult};
10
11use crate::{ArbPrecompileError, interfaces::IArbOwnerPublic};
12
13pub const ARBOWNERPUBLIC_ADDRESS: Address = Address::new([
15 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
16 0x00, 0x00, 0x00, 0x6b,
17]);
18
19const SLOAD_GAS: u64 = 800;
20const SSTORE_GAS: u64 = 20_000;
21const COPY_GAS: u64 = 3;
22
23pub fn create_arbownerpublic_precompile(ctx: Arc<ArbPrecompileCtx>) -> DynPrecompile {
24 DynPrecompile::new_stateful(PrecompileId::custom("arbownerpublic"), move |input| {
25 handler(input, &ctx)
26 })
27}
28
29fn handler(mut input: PrecompileInput<'_>, ctx: &ArbPrecompileCtx) -> PrecompileResult {
30 let mut gas_used = 0u64;
31 let gas_limit = input.gas;
32 crate::init_precompile_gas(&mut gas_used, ctx, input.data.len());
33
34 let call = match IArbOwnerPublic::ArbOwnerPublicCalls::abi_decode(input.data) {
35 Ok(c) => c,
36 Err(_) => return crate::burn_all_revert(gas_limit),
37 };
38 if let Some(r) = crate::reject_nonpayable_value(input.value, input.data, gas_limit, &[]) {
39 return r;
40 }
41 if let Some(r) = crate::reject_static_write(
42 input.is_static,
43 input.data,
44 gas_limit,
45 &[[0x6f, 0xe8, 0x63, 0x73]],
46 ) {
47 return r;
48 }
49 if let Some(r) = crate::reject_delegate_nonpure(
50 input.target_address != input.bytecode_address,
51 input.data,
52 gas_limit,
53 &[],
54 ) {
55 return r;
56 }
57
58 use IArbOwnerPublic::ArbOwnerPublicCalls as Calls;
59 let result = match call {
60 Calls::getNetworkFeeAccount(_) => read_network_fee_account(&mut input, &mut gas_used, ctx),
61 Calls::getInfraFeeAccount(_) => {
62 if let Some(r) = crate::check_method_version(
63 ctx,
64 gas_limit,
65 arb_chainspec::arbos_version::ARBOS_VERSION_5,
66 0,
67 ) {
68 return r;
69 }
70 read_infra_fee_account(&mut input, &mut gas_used, ctx)
71 }
72 Calls::getBrotliCompressionLevel(_) => {
73 if let Some(r) = crate::check_method_version(
74 ctx,
75 gas_limit,
76 arb_chainspec::arbos_version::ARBOS_VERSION_20,
77 0,
78 ) {
79 return r;
80 }
81 read_brotli_compression_level(&mut input, &mut gas_used, ctx)
82 }
83 Calls::getScheduledUpgrade(_) => {
84 if let Some(r) = crate::check_method_version(
85 ctx,
86 gas_limit,
87 arb_chainspec::arbos_version::ARBOS_VERSION_20,
88 0,
89 ) {
90 return r;
91 }
92 handle_scheduled_upgrade(&mut input, &mut gas_used, ctx)
93 }
94 Calls::isChainOwner(c) => handle_is_chain_owner(&mut input, &mut gas_used, c.addr, ctx),
95 Calls::getAllChainOwners(_) => handle_get_all_chain_owners(&mut input, &mut gas_used, ctx),
96 Calls::rectifyChainOwner(c) => {
97 if let Some(r) = crate::check_method_version(
98 ctx,
99 gas_limit,
100 arb_chainspec::arbos_version::ARBOS_VERSION_11,
101 0,
102 ) {
103 return r;
104 }
105 handle_rectify_chain_owner(&mut input, &mut gas_used, c.ownerToRectify, ctx)
106 }
107 Calls::isNativeTokenOwner(c) => {
108 if let Some(r) = crate::check_method_version(
109 ctx,
110 gas_limit,
111 arb_chainspec::arbos_version::ARBOS_VERSION_41,
112 0,
113 ) {
114 return r;
115 }
116 handle_is_native_token_owner(&mut input, &mut gas_used, c.addr, ctx)
117 }
118 Calls::isTransactionFilterer(c) => {
119 if let Some(r) = crate::check_method_version(
120 ctx,
121 gas_limit,
122 arb_chainspec::arbos_version::ARBOS_VERSION_TRANSACTION_FILTERING,
123 0,
124 ) {
125 return r;
126 }
127 handle_is_transaction_filterer(&mut input, &mut gas_used, c.filterer, ctx)
128 }
129 Calls::getAllNativeTokenOwners(_) => {
130 if let Some(r) = crate::check_method_version(
131 ctx,
132 gas_limit,
133 arb_chainspec::arbos_version::ARBOS_VERSION_41,
134 0,
135 ) {
136 return r;
137 }
138 handle_get_all_native_token_owners(&mut input, &mut gas_used, ctx)
139 }
140 Calls::getAllTransactionFilterers(_) => {
141 if let Some(r) = crate::check_method_version(
142 ctx,
143 gas_limit,
144 arb_chainspec::arbos_version::ARBOS_VERSION_TRANSACTION_FILTERING,
145 0,
146 ) {
147 return r;
148 }
149 handle_get_all_transaction_filterers(&mut input, &mut gas_used, ctx)
150 }
151 Calls::getNativeTokenManagementFrom(_) => {
152 if let Some(r) = crate::check_method_version(
153 ctx,
154 gas_limit,
155 arb_chainspec::arbos_version::ARBOS_VERSION_50,
156 0,
157 ) {
158 return r;
159 }
160 read_native_token_management_from(&mut input, &mut gas_used, ctx)
161 }
162 Calls::getTransactionFilteringFrom(_) => {
163 if let Some(r) = crate::check_method_version(
164 ctx,
165 gas_limit,
166 arb_chainspec::arbos_version::ARBOS_VERSION_TRANSACTION_FILTERING,
167 0,
168 ) {
169 return r;
170 }
171 read_transaction_filtering_from(&mut input, &mut gas_used, ctx)
172 }
173 Calls::getFilteredFundsRecipient(_) => {
174 if let Some(r) = crate::check_method_version(
175 ctx,
176 gas_limit,
177 arb_chainspec::arbos_version::ARBOS_VERSION_TRANSACTION_FILTERING,
178 0,
179 ) {
180 return r;
181 }
182 read_filtered_funds_recipient(&mut input, &mut gas_used, ctx)
183 }
184 Calls::isCalldataPriceIncreaseEnabled(_) => {
185 if let Some(r) = crate::check_method_version(
186 ctx,
187 gas_limit,
188 arb_chainspec::arbos_version::ARBOS_VERSION_40,
189 0,
190 ) {
191 return r;
192 }
193 handle_is_calldata_price_increase_enabled(&mut input, &mut gas_used, ctx)
194 }
195 Calls::getParentGasFloorPerToken(_) => {
196 if let Some(r) = crate::check_method_version(
197 ctx,
198 gas_limit,
199 arb_chainspec::arbos_version::ARBOS_VERSION_50,
200 0,
201 ) {
202 return r;
203 }
204 read_parent_gas_floor_per_token(&mut input, &mut gas_used, ctx)
205 }
206 Calls::getMaxStylusContractFragments(_) => {
207 if let Some(r) = crate::check_method_version(
208 ctx,
209 gas_limit,
210 arb_chainspec::arbos_version::ARBOS_VERSION_60,
211 0,
212 ) {
213 return r;
214 }
215 handle_max_stylus_fragments(&mut input, &mut gas_used, ctx)
216 }
217 Calls::getCollectTips(_) => {
218 if let Some(r) = crate::check_method_version(
219 ctx,
220 gas_limit,
221 arb_chainspec::arbos_version::ARBOS_VERSION_60,
222 0,
223 ) {
224 return r;
225 }
226 handle_get_collect_tips(&mut input, &mut gas_used, ctx)
227 }
228 };
229 crate::gas_check(ctx, gas_limit, gas_used, result)
230}
231
232fn load_arbos(input: &mut PrecompileInput<'_>) -> Result<(), ArbPrecompileError> {
233 input
234 .internals_mut()
235 .load_account(ARBOS_STATE_ADDRESS)
236 .map_err(ArbPrecompileError::fatal)?;
237 Ok(())
238}
239
240fn field_read_output(
241 gas_used: &mut u64,
242 ctx: &ArbPrecompileCtx,
243 gas_limit: u64,
244 value: U256,
245) -> PrecompileResult {
246 crate::charge_storage_read(gas_used, ctx, SLOAD_GAS);
247 crate::charge_computation(gas_used, ctx, COPY_GAS);
248 Ok(PrecompileOutput::new(
249 (*gas_used).min(gas_limit),
250 value.to_be_bytes::<32>().to_vec().into(),
251 ))
252}
253
254fn read_network_fee_account(
255 input: &mut PrecompileInput<'_>,
256 gas_used: &mut u64,
257 ctx: &ArbPrecompileCtx,
258) -> PrecompileResult {
259 let gas_limit = input.gas;
260 load_arbos(input)?;
261 let internals = input.internals_mut();
262 let arb_state = ctx
263 .block
264 .arbos_state(internals)
265 .map_err(ArbPrecompileError::fatal)?;
266 let addr = arb_state
267 .network_fee_account(internals)
268 .map_err(ArbPrecompileError::fatal)?;
269 field_read_output(
270 gas_used,
271 ctx,
272 gas_limit,
273 U256::from_be_slice(addr.as_slice()),
274 )
275}
276
277fn read_infra_fee_account(
278 input: &mut PrecompileInput<'_>,
279 gas_used: &mut u64,
280 ctx: &ArbPrecompileCtx,
281) -> PrecompileResult {
282 let gas_limit = input.gas;
283 load_arbos(input)?;
284 let internals = input.internals_mut();
285 let arb_state = ctx
286 .block
287 .arbos_state(internals)
288 .map_err(ArbPrecompileError::fatal)?;
289 let addr = if ctx.block.arbos_version < arb_chainspec::arbos_version::ARBOS_VERSION_6 {
290 arb_state
291 .network_fee_account(internals)
292 .map_err(ArbPrecompileError::fatal)?
293 } else {
294 arb_state
295 .infra_fee_account(internals)
296 .map_err(ArbPrecompileError::fatal)?
297 };
298 field_read_output(
299 gas_used,
300 ctx,
301 gas_limit,
302 U256::from_be_slice(addr.as_slice()),
303 )
304}
305
306fn read_brotli_compression_level(
307 input: &mut PrecompileInput<'_>,
308 gas_used: &mut u64,
309 ctx: &ArbPrecompileCtx,
310) -> PrecompileResult {
311 let gas_limit = input.gas;
312 load_arbos(input)?;
313 let internals = input.internals_mut();
314 let arb_state = ctx
315 .block
316 .arbos_state(internals)
317 .map_err(ArbPrecompileError::fatal)?;
318 let value = arb_state
319 .brotli_compression_level(internals)
320 .map_err(ArbPrecompileError::fatal)?;
321 field_read_output(gas_used, ctx, gas_limit, U256::from(value))
322}
323
324fn read_native_token_management_from(
325 input: &mut PrecompileInput<'_>,
326 gas_used: &mut u64,
327 ctx: &ArbPrecompileCtx,
328) -> PrecompileResult {
329 let gas_limit = input.gas;
330 load_arbos(input)?;
331 let internals = input.internals_mut();
332 let arb_state = ctx
333 .block
334 .arbos_state(internals)
335 .map_err(ArbPrecompileError::fatal)?;
336 let value = arb_state
337 .native_token_management_from_time(internals)
338 .map_err(ArbPrecompileError::fatal)?;
339 field_read_output(gas_used, ctx, gas_limit, U256::from(value))
340}
341
342fn read_transaction_filtering_from(
343 input: &mut PrecompileInput<'_>,
344 gas_used: &mut u64,
345 ctx: &ArbPrecompileCtx,
346) -> PrecompileResult {
347 let gas_limit = input.gas;
348 load_arbos(input)?;
349 let internals = input.internals_mut();
350 let arb_state = ctx
351 .block
352 .arbos_state(internals)
353 .map_err(ArbPrecompileError::fatal)?;
354 let value = arb_state
355 .transaction_filtering_from_time(internals)
356 .map_err(ArbPrecompileError::fatal)?;
357 field_read_output(gas_used, ctx, gas_limit, U256::from(value))
358}
359
360fn read_filtered_funds_recipient(
361 input: &mut PrecompileInput<'_>,
362 gas_used: &mut u64,
363 ctx: &ArbPrecompileCtx,
364) -> PrecompileResult {
365 let gas_limit = input.gas;
366 load_arbos(input)?;
367 let internals = input.internals_mut();
368 let arb_state = ctx
369 .block
370 .arbos_state(internals)
371 .map_err(ArbPrecompileError::fatal)?;
372 let addr = arb_state
373 .filtered_funds_recipient(internals)
374 .map_err(ArbPrecompileError::fatal)?;
375 field_read_output(
376 gas_used,
377 ctx,
378 gas_limit,
379 U256::from_be_slice(addr.as_slice()),
380 )
381}
382
383fn read_parent_gas_floor_per_token(
384 input: &mut PrecompileInput<'_>,
385 gas_used: &mut u64,
386 ctx: &ArbPrecompileCtx,
387) -> PrecompileResult {
388 let gas_limit = input.gas;
389 load_arbos(input)?;
390 let internals = input.internals_mut();
391 let arb_state = ctx
392 .block
393 .arbos_state(internals)
394 .map_err(ArbPrecompileError::fatal)?;
395 let value = arb_state
396 .l1_pricing_state
397 .parent_gas_floor_per_token(internals)
398 .map_err(ArbPrecompileError::fatal)?;
399 field_read_output(gas_used, ctx, gas_limit, U256::from(value))
400}
401
402fn handle_scheduled_upgrade(
403 input: &mut PrecompileInput<'_>,
404 gas_used: &mut u64,
405 ctx: &ArbPrecompileCtx,
406) -> PrecompileResult {
407 let gas_limit = input.gas;
408 load_arbos(input)?;
409 let internals = input.internals_mut();
410 let arb_state = ctx
411 .block
412 .arbos_state(internals)
413 .map_err(ArbPrecompileError::fatal)?;
414 let (mut version, mut timestamp) = arb_state
415 .get_scheduled_upgrade(internals)
416 .map_err(ArbPrecompileError::fatal)?;
417 if ctx.block.arbos_version >= version {
418 version = 0;
419 timestamp = 0;
420 }
421
422 let mut out = Vec::with_capacity(64);
423 out.extend_from_slice(&U256::from(version).to_be_bytes::<32>());
424 out.extend_from_slice(&U256::from(timestamp).to_be_bytes::<32>());
425
426 crate::charge_storage_read(gas_used, ctx, 2 * SLOAD_GAS);
427 crate::charge_computation(gas_used, ctx, 2 * COPY_GAS);
428 Ok(PrecompileOutput::new(
429 (*gas_used).min(gas_limit),
430 out.into(),
431 ))
432}
433
434fn handle_is_chain_owner(
435 input: &mut PrecompileInput<'_>,
436 gas_used: &mut u64,
437 addr: Address,
438 ctx: &ArbPrecompileCtx,
439) -> PrecompileResult {
440 let gas_limit = input.gas;
441 load_arbos(input)?;
442 let internals = input.internals_mut();
443 let arb_state = ctx
444 .block
445 .arbos_state(internals)
446 .map_err(ArbPrecompileError::fatal)?;
447 let is_owner = arb_state
448 .chain_owners
449 .is_member(internals, addr)
450 .map_err(ArbPrecompileError::fatal)?;
451 let result = if is_owner {
452 U256::from(1u64)
453 } else {
454 U256::ZERO
455 };
456
457 crate::charge_storage_read(gas_used, ctx, SLOAD_GAS);
458 crate::charge_computation(gas_used, ctx, COPY_GAS);
459 Ok(PrecompileOutput::new(
460 (*gas_used).min(gas_limit),
461 result.to_be_bytes::<32>().to_vec().into(),
462 ))
463}
464
465fn handle_is_native_token_owner(
466 input: &mut PrecompileInput<'_>,
467 gas_used: &mut u64,
468 addr: Address,
469 ctx: &ArbPrecompileCtx,
470) -> PrecompileResult {
471 let gas_limit = input.gas;
472 load_arbos(input)?;
473 let internals = input.internals_mut();
474 let arb_state = ctx
475 .block
476 .arbos_state(internals)
477 .map_err(ArbPrecompileError::fatal)?;
478 let is_member = arb_state
479 .native_token_owners
480 .is_member(internals, addr)
481 .map_err(ArbPrecompileError::fatal)?;
482 let result = if is_member {
483 U256::from(1u64)
484 } else {
485 U256::ZERO
486 };
487
488 crate::charge_storage_read(gas_used, ctx, SLOAD_GAS);
489 crate::charge_computation(gas_used, ctx, COPY_GAS);
490 Ok(PrecompileOutput::new(
491 (*gas_used).min(gas_limit),
492 result.to_be_bytes::<32>().to_vec().into(),
493 ))
494}
495
496fn handle_is_transaction_filterer(
497 input: &mut PrecompileInput<'_>,
498 gas_used: &mut u64,
499 addr: Address,
500 ctx: &ArbPrecompileCtx,
501) -> PrecompileResult {
502 let gas_limit = input.gas;
503 load_arbos(input)?;
504 let internals = input.internals_mut();
505 let arb_state = ctx
506 .block
507 .arbos_state(internals)
508 .map_err(ArbPrecompileError::fatal)?;
509 let is_member = arb_state
510 .transaction_filterers
511 .is_member(internals, addr)
512 .map_err(ArbPrecompileError::fatal)?;
513 let result = if is_member {
514 U256::from(1u64)
515 } else {
516 U256::ZERO
517 };
518
519 crate::charge_storage_read(gas_used, ctx, SLOAD_GAS);
520 crate::charge_computation(gas_used, ctx, COPY_GAS);
521 Ok(PrecompileOutput::new(
522 (*gas_used).min(gas_limit),
523 result.to_be_bytes::<32>().to_vec().into(),
524 ))
525}
526
527enum AddressSetKind {
528 ChainOwners,
529 NativeTokenOwners,
530 TransactionFilterers,
531}
532
533fn handle_get_all_chain_owners(
534 input: &mut PrecompileInput<'_>,
535 gas_used: &mut u64,
536 ctx: &ArbPrecompileCtx,
537) -> PrecompileResult {
538 handle_get_all_set_members(input, gas_used, AddressSetKind::ChainOwners, 256, ctx)
539}
540
541fn handle_get_all_native_token_owners(
542 input: &mut PrecompileInput<'_>,
543 gas_used: &mut u64,
544 ctx: &ArbPrecompileCtx,
545) -> PrecompileResult {
546 handle_get_all_set_members(
547 input,
548 gas_used,
549 AddressSetKind::NativeTokenOwners,
550 65_536,
551 ctx,
552 )
553}
554
555fn handle_get_all_transaction_filterers(
556 input: &mut PrecompileInput<'_>,
557 gas_used: &mut u64,
558 ctx: &ArbPrecompileCtx,
559) -> PrecompileResult {
560 handle_get_all_set_members(
561 input,
562 gas_used,
563 AddressSetKind::TransactionFilterers,
564 65_536,
565 ctx,
566 )
567}
568
569fn handle_get_all_set_members(
570 input: &mut PrecompileInput<'_>,
571 gas_used: &mut u64,
572 kind: AddressSetKind,
573 cap: u64,
574 ctx: &ArbPrecompileCtx,
575) -> PrecompileResult {
576 let gas_limit = input.gas;
577 load_arbos(input)?;
578 let internals = input.internals_mut();
579 let arb_state = ctx
580 .block
581 .arbos_state(internals)
582 .map_err(ArbPrecompileError::fatal)?;
583 let set = match kind {
584 AddressSetKind::ChainOwners => &arb_state.chain_owners,
585 AddressSetKind::NativeTokenOwners => &arb_state.native_token_owners,
586 AddressSetKind::TransactionFilterers => &arb_state.transaction_filterers,
587 };
588 let members = set
589 .all_members(internals, cap)
590 .map_err(ArbPrecompileError::fatal)?;
591 let count = members.len() as u64;
592
593 let mut out = Vec::with_capacity(64 + members.len() * 32);
594 out.extend_from_slice(&U256::from(32u64).to_be_bytes::<32>());
595 out.extend_from_slice(&U256::from(count).to_be_bytes::<32>());
596 for member in &members {
597 let mut word = [0u8; 32];
598 word[12..32].copy_from_slice(member.as_slice());
599 out.extend_from_slice(&word);
600 }
601
602 crate::charge_storage_read(gas_used, ctx, (1 + count) * SLOAD_GAS);
603 crate::charge_computation(gas_used, ctx, (2 + count) * COPY_GAS);
604 Ok(PrecompileOutput::new(
605 (*gas_used).min(gas_limit),
606 out.into(),
607 ))
608}
609
610fn handle_rectify_chain_owner(
611 input: &mut PrecompileInput<'_>,
612 gas_used: &mut u64,
613 addr: Address,
614 ctx: &ArbPrecompileCtx,
615) -> PrecompileResult {
616 let gas_limit = input.gas;
617 load_arbos(input)?;
618
619 let internals = input.internals_mut();
620 let arb_state = ctx
621 .block
622 .arbos_state(internals)
623 .map_err(ArbPrecompileError::fatal)?;
624
625 match arb_state.chain_owners.rectify_mapping(internals, addr) {
626 Ok(()) => {}
627 Err(AddressSetError::Storage(s)) => return Err(ArbPrecompileError::fatal(s).into()),
628 Err(AddressSetError::NotMember) => {
629 crate::charge_storage_read(gas_used, ctx, SLOAD_GAS);
630 return Err(ArbPrecompileError::empty_revert(*gas_used).into());
631 }
632 Err(AddressSetError::MappingAlreadyConsistent) => {
633 crate::charge_storage_read(gas_used, ctx, 4 * SLOAD_GAS);
634 return Err(ArbPrecompileError::empty_revert(*gas_used).into());
635 }
636 }
637
638 let topic0 = alloy_primitives::keccak256("ChainOwnerRectified(address)");
639 let addr_hash = alloy_primitives::B256::left_padding_from(addr.as_slice());
640 input
641 .internals_mut()
642 .log(alloy_primitives::Log::new_unchecked(
643 ARBOWNERPUBLIC_ADDRESS,
644 vec![topic0],
645 addr_hash.0.to_vec().into(),
646 ));
647
648 const SSTORE_ZERO_GAS: u64 = 5_000;
649 const RECTIFY_EVENT_GAS: u64 = 1_006;
650 crate::charge_storage_read(gas_used, ctx, 7 * SLOAD_GAS);
651 crate::charge_storage_write(gas_used, ctx, SSTORE_ZERO_GAS + 3 * SSTORE_GAS);
652 crate::charge_history_growth(gas_used, ctx, RECTIFY_EVENT_GAS);
653 Ok(PrecompileOutput::new(
655 (*gas_used).min(gas_limit),
656 Vec::new().into(),
657 ))
658}
659
660fn handle_is_calldata_price_increase_enabled(
661 input: &mut PrecompileInput<'_>,
662 gas_used: &mut u64,
663 ctx: &ArbPrecompileCtx,
664) -> PrecompileResult {
665 let gas_limit = input.gas;
666 load_arbos(input)?;
667 let internals = input.internals_mut();
668 let arb_state = ctx
669 .block
670 .arbos_state(internals)
671 .map_err(ArbPrecompileError::fatal)?;
672 let enabled = arb_state
673 .features
674 .is_increased_calldata_price_enabled(internals)
675 .map_err(ArbPrecompileError::fatal)?;
676 let value = if enabled {
677 U256::from(1u64)
678 } else {
679 U256::ZERO
680 };
681 crate::charge_storage_read(gas_used, ctx, SLOAD_GAS);
682 crate::charge_computation(gas_used, ctx, COPY_GAS);
683 Ok(PrecompileOutput::new(
684 (*gas_used).min(gas_limit),
685 value.to_be_bytes::<32>().to_vec().into(),
686 ))
687}
688
689fn handle_max_stylus_fragments(
690 input: &mut PrecompileInput<'_>,
691 gas_used: &mut u64,
692 ctx: &ArbPrecompileCtx,
693) -> PrecompileResult {
694 let gas_limit = input.gas;
695 load_arbos(input)?;
696 let internals = input.internals_mut();
697 let arb_state = ctx
698 .block
699 .arbos_state(internals)
700 .map_err(ArbPrecompileError::fatal)?;
701 let params = arb_state
702 .programs
703 .params(internals)
704 .map_err(ArbPrecompileError::fatal)?;
705 let mut count = params.max_fragment_count;
706 if count == 0 {
707 count = arbos::programs::params::INITIAL_MAX_FRAGMENT_COUNT;
708 }
709 let mut out = [0u8; 32];
710 out[31] = count;
711 crate::charge_params_read(gas_used, ctx);
712 crate::charge_computation(gas_used, ctx, COPY_GAS);
713 Ok(PrecompileOutput::new(
714 (*gas_used).min(gas_limit),
715 out.to_vec().into(),
716 ))
717}
718
719fn handle_get_collect_tips(
720 input: &mut PrecompileInput<'_>,
721 gas_used: &mut u64,
722 ctx: &ArbPrecompileCtx,
723) -> PrecompileResult {
724 let gas_limit = input.gas;
725 load_arbos(input)?;
726 let internals = input.internals_mut();
727 let arb_state = ctx
728 .block
729 .arbos_state(internals)
730 .map_err(ArbPrecompileError::fatal)?;
731 let value = arb_state
732 .collect_tips(internals)
733 .map_err(ArbPrecompileError::fatal)?;
734
735 let mut out = [0u8; 32];
736 if value {
737 out[31] = 1;
738 }
739 crate::charge_storage_read(gas_used, ctx, SLOAD_GAS);
740 crate::charge_computation(gas_used, ctx, COPY_GAS);
741 Ok(PrecompileOutput::new(
742 (*gas_used).min(gas_limit),
743 out.to_vec().into(),
744 ))
745}