revm_bytecode/
eip7702.rs

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