alloy_primitives/bits/
function.rs

1use crate::{Address, FixedBytes, Selector};
2use core::borrow::Borrow;
3
4wrap_fixed_bytes! {
5    /// An Ethereum ABI function pointer, 24 bytes in length.
6    ///
7    /// An address (20 bytes), followed by a function selector (4 bytes).
8    /// Encoded identical to `bytes24`.
9    pub struct Function<24>;
10}
11
12impl<A, S> From<(A, S)> for Function
13where
14    A: Borrow<[u8; 20]>,
15    S: Borrow<[u8; 4]>,
16{
17    #[inline]
18    fn from((address, selector): (A, S)) -> Self {
19        Self::from_address_and_selector(address, selector)
20    }
21}
22
23impl Function {
24    /// Creates an Ethereum function from an EVM word's lower 24 bytes
25    /// (`word[..24]`).
26    ///
27    /// Note that this is different from `Address::from_word`, which uses the
28    /// upper 20 bytes.
29    #[inline]
30    #[must_use]
31    pub fn from_word(word: FixedBytes<32>) -> Self {
32        Self(FixedBytes(word[..24].try_into().unwrap()))
33    }
34
35    /// Right-pads the function to 32 bytes (EVM word size).
36    ///
37    /// Note that this is different from `Address::into_word`, which left-pads
38    /// the address.
39    #[inline]
40    #[must_use]
41    pub fn into_word(&self) -> FixedBytes<32> {
42        let mut word = [0; 32];
43        word[..24].copy_from_slice(self.as_slice());
44        FixedBytes(word)
45    }
46
47    /// Creates an Ethereum function from an address and selector.
48    #[inline]
49    pub fn from_address_and_selector<A, S>(address: A, selector: S) -> Self
50    where
51        A: Borrow<[u8; 20]>,
52        S: Borrow<[u8; 4]>,
53    {
54        let mut bytes = [0; 24];
55        bytes[..20].copy_from_slice(address.borrow());
56        bytes[20..].copy_from_slice(selector.borrow());
57        Self(FixedBytes(bytes))
58    }
59
60    /// Returns references to the address and selector of the function.
61    #[inline]
62    pub fn as_address_and_selector(&self) -> (&Address, &Selector) {
63        // SAFETY: Function (24) = Address (20) + Selector (4)
64        unsafe { (&*self.as_ptr().cast(), &*self.as_ptr().add(20).cast()) }
65    }
66
67    /// Returns the address and selector of the function.
68    #[inline]
69    pub fn to_address_and_selector(&self) -> (Address, Selector) {
70        let (a, s) = self.as_address_and_selector();
71        (*a, *s)
72    }
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use crate::hex;
79
80    #[test]
81    fn function_parts() {
82        let f = Function::new(hex!(
83            "
84            ffffffffffffffffffffffffffffffffffffffff
85            12345678
86        "
87        ));
88
89        let (a1, s1) = f.as_address_and_selector();
90        assert_eq!(a1, hex!("ffffffffffffffffffffffffffffffffffffffff"));
91        assert_eq!(s1, &hex!("12345678"));
92
93        let (a2, s2) = f.to_address_and_selector();
94        assert_eq!(a2, *a1);
95        assert_eq!(s2, *s1);
96    }
97}