revm_primitives/eip7702/
bytecode.rs
1use crate::{bytes, Address, Bytes};
2use core::fmt;
3
4pub const EIP7702_MAGIC: u16 = 0xEF01;
6
7pub static EIP7702_MAGIC_BYTES: Bytes = bytes!("ef01");
9
10pub const EIP7702_VERSION: u8 = 0;
12
13#[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 #[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 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 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 #[inline]
62 pub fn raw(&self) -> &Bytes {
63 &self.raw
64 }
65
66 #[inline]
68 pub fn address(&self) -> Address {
69 self.delegated_address
70 }
71}
72
73#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
75#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
76pub enum Eip7702DecodeError {
77 InvalidLength,
79 InvalidMagic,
81 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}