tempo_precompiles/tip_account_registrar/
dispatch.rs1use crate::{Precompile, fill_precompile_output, input_cost, mutate, unknown_selector};
2use alloy::{primitives::Address, sol_types::SolCall};
3use revm::precompile::{PrecompileError, PrecompileResult};
4
5use crate::tip_account_registrar::{ITipAccountRegistrar, TipAccountRegistrar};
6
7impl Precompile for TipAccountRegistrar {
8 fn call(&mut self, calldata: &[u8], msg_sender: Address) -> PrecompileResult {
9 self.storage
10 .deduct_gas(input_cost(calldata.len()))
11 .map_err(|_| PrecompileError::OutOfGas)?;
12
13 let selector: [u8; 4] = calldata
14 .get(..4)
15 .ok_or_else(|| {
16 PrecompileError::Other("Invalid input: missing function selector".into())
17 })?
18 .try_into()
19 .unwrap();
20
21 let result = match selector {
22 ITipAccountRegistrar::delegateToDefault_0Call::SELECTOR => {
24 if self.storage.spec().is_moderato() {
25 unknown_selector(selector, self.storage.gas_used(), self.storage.spec())
26 } else {
27 mutate::<ITipAccountRegistrar::delegateToDefault_0Call>(
28 calldata,
29 msg_sender,
30 |_, call| self.delegate_to_default_v1(call),
31 )
32 }
33 }
34 ITipAccountRegistrar::delegateToDefault_1Call::SELECTOR => {
36 if self.storage.spec().is_moderato() {
37 mutate::<ITipAccountRegistrar::delegateToDefault_1Call>(
38 calldata,
39 msg_sender,
40 |_, call| self.delegate_to_default_v2(call),
41 )
42 } else {
43 unknown_selector(selector, self.storage.gas_used(), self.storage.spec())
44 }
45 }
46 _ => unknown_selector(selector, self.storage.gas_used(), self.storage.spec()),
47 };
48
49 result.map(|res| fill_precompile_output(res, &mut self.storage))
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use crate::{
57 storage::{StorageCtx, hashmap::HashMapStorageProvider},
58 test_util::check_selector_coverage,
59 };
60 use tempo_chainspec::hardfork::TempoHardfork;
61 use tempo_contracts::precompiles::ITipAccountRegistrar::ITipAccountRegistrarCalls;
62
63 #[test]
64 fn test_selector_coverage_pre_moderato() -> eyre::Result<()> {
65 let mut storage = HashMapStorageProvider::new(1).with_spec(TempoHardfork::Adagio);
66 StorageCtx::enter(&mut storage, || {
67 let mut registrar = TipAccountRegistrar::new();
69
70 let unsupported_pre = check_selector_coverage(
71 &mut registrar,
72 ITipAccountRegistrarCalls::SELECTORS,
73 "ITipAccountRegistrar (pre-Moderato)",
74 ITipAccountRegistrarCalls::name_by_selector,
75 );
76
77 assert_eq!(
79 unsupported_pre.len(),
80 1,
81 "Expected 1 unsupported selector pre-Moderato, got {}",
82 unsupported_pre.len()
83 );
84 assert_eq!(
85 unsupported_pre[0].0,
86 ITipAccountRegistrar::delegateToDefault_1Call::SELECTOR,
87 "Expected delegateToDefault v2 to be unsupported pre-Moderato"
88 );
89
90 Ok(())
91 })
92 }
93
94 #[test]
95 fn test_selector_coverage_post_moderato() -> eyre::Result<()> {
96 let mut storage = HashMapStorageProvider::new(1).with_spec(TempoHardfork::Moderato);
97 StorageCtx::enter(&mut storage, || {
98 let mut registrar = TipAccountRegistrar::new();
100
101 let unsupported_post = check_selector_coverage(
102 &mut registrar,
103 ITipAccountRegistrarCalls::SELECTORS,
104 "ITipAccountRegistrar (post-Moderato)",
105 ITipAccountRegistrarCalls::name_by_selector,
106 );
107
108 assert_eq!(
110 unsupported_post.len(),
111 1,
112 "Expected 1 unsupported selector post-Moderato, got {}",
113 unsupported_post.len()
114 );
115 assert_eq!(
116 unsupported_post[0].0,
117 ITipAccountRegistrar::delegateToDefault_0Call::SELECTOR,
118 "Expected delegateToDefault v1 to be unsupported post-Moderato"
119 );
120
121 Ok(())
122 })
123 }
124}