kona_genesis/updates/
operator_fee.rs1use alloy_primitives::LogData;
4use alloy_sol_types::{SolType, sol};
5
6use crate::{OperatorFeeUpdateError, SystemConfig, SystemConfigLog};
7
8#[derive(Debug, Default, Clone, Hash, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct OperatorFeeUpdate {
12 pub operator_fee_scalar: u32,
14 pub operator_fee_constant: u64,
16}
17
18impl OperatorFeeUpdate {
19 pub const fn apply(&self, config: &mut SystemConfig) {
21 config.operator_fee_scalar = Some(self.operator_fee_scalar);
22 config.operator_fee_constant = Some(self.operator_fee_constant);
23 }
24}
25
26impl TryFrom<&SystemConfigLog> for OperatorFeeUpdate {
27 type Error = OperatorFeeUpdateError;
28
29 fn try_from(log: &SystemConfigLog) -> Result<Self, Self::Error> {
30 let LogData { data, .. } = &log.log.data;
31 if data.len() != 96 {
32 return Err(OperatorFeeUpdateError::InvalidDataLen(data.len()));
33 }
34
35 let Ok(pointer) = <sol!(uint64)>::abi_decode_validate(&data[0..32]) else {
36 return Err(OperatorFeeUpdateError::PointerDecodingError);
37 };
38 if pointer != 32 {
39 return Err(OperatorFeeUpdateError::InvalidDataPointer(pointer));
40 }
41
42 let Ok(length) = <sol!(uint64)>::abi_decode_validate(&data[32..64]) else {
43 return Err(OperatorFeeUpdateError::LengthDecodingError);
44 };
45 if length != 32 {
46 return Err(OperatorFeeUpdateError::InvalidDataLength(length));
47 }
48
49 let mut be_bytes = [0u8; 4];
59 be_bytes[0..4].copy_from_slice(&data[84..88]);
60 let operator_fee_scalar = u32::from_be_bytes(be_bytes);
61
62 let mut be_bytes = [0u8; 8];
63 be_bytes[0..8].copy_from_slice(&data[88..96]);
64 let operator_fee_constant = u64::from_be_bytes(be_bytes);
65
66 Ok(Self { operator_fee_scalar, operator_fee_constant })
67 }
68}
69
70#[cfg(test)]
71mod tests {
72 use super::*;
73 use crate::{CONFIG_UPDATE_EVENT_VERSION_0, CONFIG_UPDATE_TOPIC};
74 use alloc::vec;
75 use alloy_primitives::{Address, B256, Bytes, Log, LogData, hex};
76
77 #[test]
78 fn test_operator_fee_update_try_from() {
79 let log = Log {
80 address: Address::ZERO,
81 data: LogData::new_unchecked(
82 vec![], hex!("0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000babe000000000000beef").into()
84 )
85 };
86
87 let system_log = SystemConfigLog::new(log, false);
88 let update = OperatorFeeUpdate::try_from(&system_log).unwrap();
89
90 assert_eq!(update.operator_fee_scalar, 0xbabe_u32);
91 assert_eq!(update.operator_fee_constant, 0xbeef_u64);
92 }
93
94 #[test]
95 fn test_operator_fee_update_invalid_data_len() {
96 let log =
97 Log { address: Address::ZERO, data: LogData::new_unchecked(vec![], Bytes::default()) };
98 let system_log = SystemConfigLog::new(log, false);
99 let err = OperatorFeeUpdate::try_from(&system_log).unwrap_err();
100 assert_eq!(err, OperatorFeeUpdateError::InvalidDataLen(0));
101 }
102
103 #[test]
104 fn test_operator_fee_update_pointer_decoding_error() {
105 let log = Log {
106 address: Address::ZERO,
107 data: LogData::new_unchecked(
108 vec![
109 CONFIG_UPDATE_TOPIC,
110 CONFIG_UPDATE_EVENT_VERSION_0,
111 B256::ZERO,
112 ],
113 hex!("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000babe0000beef").into()
114 )
115 };
116
117 let system_log = SystemConfigLog::new(log, false);
118 let err = OperatorFeeUpdate::try_from(&system_log).unwrap_err();
119 assert_eq!(err, OperatorFeeUpdateError::PointerDecodingError);
120 }
121
122 #[test]
123 fn test_operator_fee_update_invalid_pointer_length() {
124 let log = Log {
125 address: Address::ZERO,
126 data: LogData::new_unchecked(
127 vec![
128 CONFIG_UPDATE_TOPIC,
129 CONFIG_UPDATE_EVENT_VERSION_0,
130 B256::ZERO,
131 ],
132 hex!("000000000000000000000000000000000000000000000000000000000000002100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000babe0000beef").into()
133 )
134 };
135
136 let system_log = SystemConfigLog::new(log, false);
137 let err = OperatorFeeUpdate::try_from(&system_log).unwrap_err();
138 assert_eq!(err, OperatorFeeUpdateError::InvalidDataPointer(33));
139 }
140
141 #[test]
142 fn test_operator_fee_update_length_decoding_error() {
143 let log = Log {
144 address: Address::ZERO,
145 data: LogData::new_unchecked(
146 vec![
147 CONFIG_UPDATE_TOPIC,
148 CONFIG_UPDATE_EVENT_VERSION_0,
149 B256::ZERO,
150 ],
151 hex!("0000000000000000000000000000000000000000000000000000000000000020FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0000000000000000000000000000000000000000000000000000babe0000beef").into()
152 )
153 };
154
155 let system_log = SystemConfigLog::new(log, false);
156 let err = OperatorFeeUpdate::try_from(&system_log).unwrap_err();
157 assert_eq!(err, OperatorFeeUpdateError::LengthDecodingError);
158 }
159
160 #[test]
161 fn test_operator_fee_update_invalid_data_length() {
162 let log = Log {
163 address: Address::ZERO,
164 data: LogData::new_unchecked(
165 vec![
166 CONFIG_UPDATE_TOPIC,
167 CONFIG_UPDATE_EVENT_VERSION_0,
168 B256::ZERO,
169 ],
170 hex!("000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000babe0000beef").into()
171 )
172 };
173
174 let system_log = SystemConfigLog::new(log, false);
175 let err = OperatorFeeUpdate::try_from(&system_log).unwrap_err();
176 assert_eq!(err, OperatorFeeUpdateError::InvalidDataLength(33));
177 }
178}