revm_primitives/eip7702/
bytecode.rs

1use crate::{bytes, Address, Bytes};
2use core::fmt;
3
4/// EIP-7702 Version Magic in u16 form.
5pub const EIP7702_MAGIC: u16 = 0xEF01;
6
7/// EIP-7702 magic number in array form.
8pub static EIP7702_MAGIC_BYTES: Bytes = bytes!("ef01");
9
10/// EIP-7702 first version of bytecode.
11pub const EIP7702_VERSION: u8 = 0;
12
13/// Bytecode of delegated account, specified in EIP-7702
14///
15/// Format of EIP-7702 bytecode consist of:
16/// 0xEF00 (MAGIC) + 0x00 (VERSION) + 20 bytes of address.
17#[derive(Clone, Debug, PartialEq, Eq, Hash)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub struct Eip7702Bytecode {
20    pub delegated_address: Address,
21    pub version: u8,
22    pub raw: Bytes,
23}
24
25impl Eip7702Bytecode {
26    /// Creates a new EIP-7702 bytecode or returns None if the raw bytecode is invalid.
27    #[inline]
28    pub fn new_raw(raw: Bytes) -> Result<Self, Eip7702DecodeError> {
29        if raw.len() != 23 {
30            return Err(Eip7702DecodeError::InvalidLength);
31        }
32        if !raw.starts_with(&EIP7702_MAGIC_BYTES) {
33            return Err(Eip7702DecodeError::InvalidMagic);
34        }
35
36        // Only supported version is version 0.
37        if raw[2] != EIP7702_VERSION {
38            return Err(Eip7702DecodeError::UnsupportedVersion);
39        }
40
41        Ok(Self {
42            delegated_address: Address::new(raw[3..].try_into().unwrap()),
43            version: EIP7702_VERSION,
44            raw,
45        })
46    }
47
48    /// Creates a new EIP-7702 bytecode with the given address.
49    pub fn new(address: Address) -> Self {
50        let mut raw = EIP7702_MAGIC_BYTES.to_vec();
51        raw.push(EIP7702_VERSION);
52        raw.extend(&address);
53        Self {
54            delegated_address: address,
55            version: EIP7702_VERSION,
56            raw: raw.into(),
57        }
58    }
59
60    /// Return the raw bytecode with version MAGIC number.
61    #[inline]
62    pub fn raw(&self) -> &Bytes {
63        &self.raw
64    }
65
66    /// Return the address of the delegated contract.
67    #[inline]
68    pub fn address(&self) -> Address {
69        self.delegated_address
70    }
71}
72
73/// Bytecode errors.
74#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
75#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
76pub enum Eip7702DecodeError {
77    /// Invalid length of the raw bytecode. It should be 23 bytes.
78    InvalidLength,
79    /// All Eip7702 bytecodes should start with the magic number 0xEF01.
80    InvalidMagic,
81    /// Only supported version is version 0x00.
82    UnsupportedVersion,
83}
84
85impl fmt::Display for Eip7702DecodeError {
86    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87        let s = match self {
88            Self::InvalidLength => "Eip7702 is not 23 bytes long",
89            Self::InvalidMagic => "Bytecode is not starting with 0xEF01",
90            Self::UnsupportedVersion => "Unsupported Eip7702 version.",
91        };
92        f.write_str(s)
93    }
94}
95
96#[cfg(feature = "std")]
97impl std::error::Error for Eip7702DecodeError {}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn sanity_decode() {
105        let raw = bytes!("ef01deadbeef");
106        assert_eq!(
107            Eip7702Bytecode::new_raw(raw),
108            Err(Eip7702DecodeError::InvalidLength)
109        );
110
111        let raw = bytes!("ef0101deadbeef00000000000000000000000000000000");
112        assert_eq!(
113            Eip7702Bytecode::new_raw(raw),
114            Err(Eip7702DecodeError::UnsupportedVersion)
115        );
116
117        let raw = bytes!("ef0100deadbeef00000000000000000000000000000000");
118        let address = raw[3..].try_into().unwrap();
119        assert_eq!(
120            Eip7702Bytecode::new_raw(raw.clone()),
121            Ok(Eip7702Bytecode {
122                delegated_address: address,
123                version: 0,
124                raw,
125            })
126        );
127    }
128
129    #[test]
130    fn create_eip7702_bytecode_from_address() {
131        let address = Address::new([0x01; 20]);
132        let bytecode = Eip7702Bytecode::new(address);
133        assert_eq!(bytecode.delegated_address, address);
134        assert_eq!(
135            bytecode.raw,
136            bytes!("ef01000101010101010101010101010101010101010101")
137        );
138    }
139}