tempo_precompiles/address_registry/
dispatch.rs1use 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 IAddressRegistryCalls::registerVirtualMaster(call) => {
22 mutate(call, msg_sender, |s, c| self.register_virtual_master(s, c))
23 }
24 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 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 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 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 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}