degenbot_executor/
config.rs1use alloy::primitives::U256;
15
16use crate::encoders::MAX_INDEXED_ADDRESSES;
17
18pub const MAX_BRIBE_BIPS: u16 = 10_000;
20
21pub const MAX_CHECK_MODE: u8 = 3;
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq, thiserror::Error)]
26pub enum ConfigError {
27 #[error("check_mode must be 0–3, got {0}")]
29 CheckModeOutOfRange(u8),
30 #[error("bribe_bips must be 0–10000, got {0}")]
32 BribeBipsOutOfRange(u16),
33 #[error("bribe_recipient_idx must be 0–31, got {0}")]
35 BribeRecipientOutOfRange(u8),
36}
37
38pub fn pack_config(
50 check_mode: u8,
51 expected_value: U256,
52 bribe_bips: u16,
53 bribe_recipient_idx: u8,
54) -> Result<U256, ConfigError> {
55 if check_mode > MAX_CHECK_MODE {
56 return Err(ConfigError::CheckModeOutOfRange(check_mode));
57 }
58 if bribe_bips > MAX_BRIBE_BIPS {
59 return Err(ConfigError::BribeBipsOutOfRange(bribe_bips));
60 }
61 if bribe_recipient_idx as usize >= MAX_INDEXED_ADDRESSES {
64 return Err(ConfigError::BribeRecipientOutOfRange(bribe_recipient_idx));
65 }
66
67 Ok((expected_value << U256::from(32u64))
69 | (U256::from(bribe_recipient_idx) << U256::from(24u64))
70 | (U256::from(bribe_bips) << U256::from(8u64))
71 | U256::from(check_mode))
72}
73
74#[cfg(test)]
75#[expect(clippy::unwrap_used)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn pack_default() {
81 assert_eq!(pack_config(0, U256::ZERO, 0, 0).unwrap(), U256::ZERO);
83 }
84
85 #[test]
86 fn pack_check_mode_only() {
87 assert_eq!(pack_config(1, U256::ZERO, 0, 0).unwrap(), U256::from(1u64));
89 }
90
91 #[test]
92 fn pack_bribe_bips_in_byte_2_3() {
93 assert_eq!(
95 pack_config(0, U256::ZERO, 100, 0).unwrap(),
96 U256::from(25_600u64)
97 );
98 }
99
100 #[test]
101 fn pack_recipient_in_byte_3() {
102 assert_eq!(
104 pack_config(0, U256::ZERO, 0, 5).unwrap(),
105 U256::from(83_886_080u64)
106 );
107 }
108
109 #[test]
110 fn pack_expected_value_high_bits() {
111 let v = U256::from(0x12345u64);
113 let packed = pack_config(0, v, 0, 0).unwrap();
114 assert_eq!(packed, v << U256::from(32u64));
115 }
116
117 #[test]
118 fn pack_all_fields_compose() {
119 let expected = U256::from(0xABCu64);
121 let expected_shifted = expected << U256::from(32u64);
122 let bribe = U256::from(500u64) << U256::from(8u64);
123 let recip = U256::from(3u64) << U256::from(24u64);
124 let mode = U256::from(2u64);
125 let want = expected_shifted | recip | bribe | mode;
126 assert_eq!(pack_config(2, expected, 500, 3).unwrap(), want);
127 }
128
129 #[test]
130 fn reject_check_mode_out_of_range() {
131 assert_eq!(pack_config(3, U256::ZERO, 0, 0), Ok(U256::from(3u64)));
132 assert_eq!(
133 pack_config(4, U256::ZERO, 0, 0),
134 Err(ConfigError::CheckModeOutOfRange(4))
135 );
136 }
137
138 #[test]
139 fn reject_bribe_bips_out_of_range() {
140 assert_eq!(
141 pack_config(0, U256::ZERO, 10_001, 0),
142 Err(ConfigError::BribeBipsOutOfRange(10_001)),
143 );
144 }
145
146 #[test]
147 fn reject_recipient_out_of_range() {
148 assert_eq!(
150 pack_config(0, U256::ZERO, 0, 32),
151 Err(ConfigError::BribeRecipientOutOfRange(32)),
152 );
153 }
154
155 #[test]
156 fn accept_recipient_at_upper_bound() {
157 assert!(pack_config(0, U256::ZERO, 0, 31).is_ok());
159 }
160
161 #[test]
162 fn accept_bribe_at_upper_bound() {
163 assert!(pack_config(0, U256::ZERO, 10_000, 0).is_ok());
164 }
165
166 #[test]
167 fn pack_large_expected_value_no_overflow() {
168 let v = U256::from(1u64) << U256::from(200u64);
170 let packed = pack_config(1, v, 300, 2).unwrap();
171 let low = (2u64 << 24) | (300u64 << 8) | 1u64;
173 assert_eq!(packed & U256::from(u64::from(u32::MAX)), U256::from(low));
174 assert_eq!(packed >> U256::from(32u64), v);
175 }
176}