Skip to main content

tempo_precompiles/address_registry/
dispatch.rs

1use crate::{
2    Precompile, address_registry::AddressRegistry, charge_input_cost, dispatch_call, mutate, view,
3};
4use alloy::{primitives::Address, sol_types::SolInterface};
5use revm::precompile::PrecompileResult;
6use tempo_contracts::precompiles::IAddressRegistry::IAddressRegistryCalls;
7use tempo_primitives::{MasterId, TempoAddressExt, UserTag};
8
9impl Precompile for AddressRegistry {
10    fn call(&mut self, calldata: &[u8], msg_sender: Address) -> PrecompileResult {
11        if let Some(err) = charge_input_cost(&mut self.storage, calldata) {
12            return err;
13        }
14
15        dispatch_call(
16            calldata,
17            &[],
18            IAddressRegistryCalls::abi_decode,
19            |call| match call {
20                // Registration
21                IAddressRegistryCalls::registerVirtualMaster(call) => {
22                    mutate(call, msg_sender, |s, c| self.register_virtual_master(s, c))
23                }
24                // View functions
25                IAddressRegistryCalls::getMaster(call) => view(call, |c| {
26                    Ok(self.get_master(c.masterId)?.unwrap_or(Address::ZERO))
27                }),
28                IAddressRegistryCalls::resolveRecipient(call) => {
29                    view(call, |c| self.resolve_recipient(c.to))
30                }
31                IAddressRegistryCalls::resolveVirtualAddress(call) => {
32                    view(call, |c| self.resolve_virtual_address(c.virtualAddr))
33                }
34                // Pure functions
35                IAddressRegistryCalls::isVirtualAddress(call) => {
36                    view(call, |c| Ok(c.addr.is_virtual()))
37                }
38                IAddressRegistryCalls::decodeVirtualAddress(call) => view(call, |c| {
39                    let (is_virtual, master_id, user_tag) = match c.addr.decode_virtual() {
40                        Some((mid, tag)) => (true, mid, tag),
41                        None => (false, MasterId::ZERO, UserTag::ZERO),
42                    };
43                    Ok((is_virtual, master_id, user_tag).into())
44                }),
45            },
46        )
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use crate::{
54        address_registry::IAddressRegistry,
55        storage::{StorageCtx, hashmap::HashMapStorageProvider},
56        test_util::{assert_full_coverage, check_selector_coverage},
57    };
58    use alloy::sol_types::{SolCall, SolValue};
59    use tempo_chainspec::hardfork::TempoHardfork;
60
61    #[test]
62    fn test_selector_coverage() -> eyre::Result<()> {
63        let mut storage = HashMapStorageProvider::new_with_spec(1, TempoHardfork::T3);
64        StorageCtx::enter(&mut storage, || {
65            let mut registry = AddressRegistry::new();
66
67            let unsupported = check_selector_coverage(
68                &mut registry,
69                IAddressRegistryCalls::SELECTORS,
70                "IAddressRegistry",
71                IAddressRegistryCalls::name_by_selector,
72            );
73
74            assert_full_coverage([unsupported]);
75
76            Ok(())
77        })
78    }
79
80    #[test]
81    fn test_get_master_precompile() -> eyre::Result<()> {
82        let mut storage = HashMapStorageProvider::new_with_spec(1, TempoHardfork::T3);
83        StorageCtx::enter(&mut storage, || {
84            let mut registry = AddressRegistry::new();
85
86            // Unregistered masterId returns address(0)
87            let call = IAddressRegistry::getMasterCall {
88                masterId: Default::default(),
89            };
90            let result = registry.call(&call.abi_encode(), Address::ZERO)?;
91            assert!(!result.is_revert());
92            let addr = Address::abi_decode(&result.bytes).unwrap();
93            assert_eq!(addr, Address::ZERO);
94
95            Ok(())
96        })
97    }
98
99    #[test]
100    fn test_is_virtual_address_precompile() -> eyre::Result<()> {
101        let mut storage = HashMapStorageProvider::new_with_spec(1, TempoHardfork::T3);
102        StorageCtx::enter(&mut storage, || {
103            let mut registry = AddressRegistry::new();
104
105            // Non-virtual
106            let call = IAddressRegistry::isVirtualAddressCall {
107                addr: Address::random(),
108            };
109            let result = registry.call(&call.abi_encode(), Address::ZERO)?;
110            assert!(!bool::abi_decode(&result.bytes).unwrap());
111
112            // Virtual
113            let mut bytes = [0u8; 20];
114            bytes[4..14].fill(0xFD);
115            let call = IAddressRegistry::isVirtualAddressCall {
116                addr: Address::from(bytes),
117            };
118            let result = registry.call(&call.abi_encode(), Address::ZERO)?;
119            assert!(bool::abi_decode(&result.bytes).unwrap());
120
121            Ok(())
122        })
123    }
124}