1use std::{
2 collections::VecDeque,
3 fmt::{self, Display},
4};
5
6use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Error, Result, Vm::*};
7use alloy_primitives::{
8 map::{hash_map::Entry, AddressHashMap, HashMap},
9 Address, Bytes, LogData as RawLog, U256,
10};
11use revm::interpreter::{InstructionResult, Interpreter, InterpreterAction, InterpreterResult};
12
13use super::revert_handlers::RevertParameters;
14pub type ExpectedCallTracker = HashMap<Address, HashMap<Bytes, (ExpectedCallData, u64)>>;
24
25#[derive(Clone, Debug)]
26pub struct ExpectedCallData {
27 pub value: Option<U256>,
29 pub gas: Option<u64>,
31 pub min_gas: Option<u64>,
33 pub count: u64,
38 pub call_type: ExpectedCallType,
40}
41
42#[derive(Clone, Debug, PartialEq, Eq)]
44pub enum ExpectedCallType {
45 NonCount,
47 Count,
49}
50
51#[derive(Clone, Debug)]
53pub enum ExpectedRevertKind {
54 Default,
56 Cheatcode { pending_processing: bool },
62}
63
64#[derive(Clone, Debug)]
65pub struct ExpectedRevert {
66 pub reason: Option<Vec<u8>>,
68 pub depth: u64,
70 pub kind: ExpectedRevertKind,
72 pub partial_match: bool,
74 pub reverter: Option<Address>,
76 pub reverted_by: Option<Address>,
78 pub max_depth: u64,
80 pub count: u64,
82 pub actual_count: u64,
84}
85
86#[derive(Clone, Debug)]
87pub struct ExpectedEmit {
88 pub depth: u64,
90 pub log: Option<RawLog>,
92 pub checks: [bool; 5],
99 pub address: Option<Address>,
101 pub anonymous: bool,
104 pub found: bool,
106 pub count: u64,
108}
109
110#[derive(Clone, Debug)]
111pub struct ExpectedCreate {
112 pub deployer: Address,
114 pub bytecode: Bytes,
116 pub create_scheme: CreateScheme,
118}
119
120#[derive(Clone, Debug)]
121pub enum CreateScheme {
122 Create,
123 Create2,
124}
125
126impl Display for CreateScheme {
127 fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
128 match self {
129 Self::Create => write!(f, "CREATE"),
130 Self::Create2 => write!(f, "CREATE2"),
131 }
132 }
133}
134
135impl CreateScheme {
136 pub fn eq(&self, create_scheme: revm::primitives::CreateScheme) -> bool {
137 matches!(
138 (self, create_scheme),
139 (Self::Create, revm::primitives::CreateScheme::Create) |
140 (Self::Create2, revm::primitives::CreateScheme::Create2 { .. })
141 )
142 }
143}
144
145impl Cheatcode for expectCall_0Call {
146 fn apply(&self, state: &mut Cheatcodes) -> Result {
147 let Self { callee, data } = self;
148 expect_call(state, callee, data, None, None, None, 1, ExpectedCallType::NonCount)
149 }
150}
151
152impl Cheatcode for expectCall_1Call {
153 fn apply(&self, state: &mut Cheatcodes) -> Result {
154 let Self { callee, data, count } = self;
155 expect_call(state, callee, data, None, None, None, *count, ExpectedCallType::Count)
156 }
157}
158
159impl Cheatcode for expectCall_2Call {
160 fn apply(&self, state: &mut Cheatcodes) -> Result {
161 let Self { callee, msgValue, data } = self;
162 expect_call(state, callee, data, Some(msgValue), None, None, 1, ExpectedCallType::NonCount)
163 }
164}
165
166impl Cheatcode for expectCall_3Call {
167 fn apply(&self, state: &mut Cheatcodes) -> Result {
168 let Self { callee, msgValue, data, count } = self;
169 expect_call(
170 state,
171 callee,
172 data,
173 Some(msgValue),
174 None,
175 None,
176 *count,
177 ExpectedCallType::Count,
178 )
179 }
180}
181
182impl Cheatcode for expectCall_4Call {
183 fn apply(&self, state: &mut Cheatcodes) -> Result {
184 let Self { callee, msgValue, gas, data } = self;
185 expect_call(
186 state,
187 callee,
188 data,
189 Some(msgValue),
190 Some(*gas),
191 None,
192 1,
193 ExpectedCallType::NonCount,
194 )
195 }
196}
197
198impl Cheatcode for expectCall_5Call {
199 fn apply(&self, state: &mut Cheatcodes) -> Result {
200 let Self { callee, msgValue, gas, data, count } = self;
201 expect_call(
202 state,
203 callee,
204 data,
205 Some(msgValue),
206 Some(*gas),
207 None,
208 *count,
209 ExpectedCallType::Count,
210 )
211 }
212}
213
214impl Cheatcode for expectCallMinGas_0Call {
215 fn apply(&self, state: &mut Cheatcodes) -> Result {
216 let Self { callee, msgValue, minGas, data } = self;
217 expect_call(
218 state,
219 callee,
220 data,
221 Some(msgValue),
222 None,
223 Some(*minGas),
224 1,
225 ExpectedCallType::NonCount,
226 )
227 }
228}
229
230impl Cheatcode for expectCallMinGas_1Call {
231 fn apply(&self, state: &mut Cheatcodes) -> Result {
232 let Self { callee, msgValue, minGas, data, count } = self;
233 expect_call(
234 state,
235 callee,
236 data,
237 Some(msgValue),
238 None,
239 Some(*minGas),
240 *count,
241 ExpectedCallType::Count,
242 )
243 }
244}
245
246impl Cheatcode for expectEmit_0Call {
247 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
248 let Self { checkTopic1, checkTopic2, checkTopic3, checkData } = *self;
249 expect_emit(
250 ccx.state,
251 ccx.ecx.journaled_state.depth(),
252 [true, checkTopic1, checkTopic2, checkTopic3, checkData],
253 None,
254 false,
255 1,
256 )
257 }
258}
259
260impl Cheatcode for expectEmit_1Call {
261 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
262 let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;
263 expect_emit(
264 ccx.state,
265 ccx.ecx.journaled_state.depth(),
266 [true, checkTopic1, checkTopic2, checkTopic3, checkData],
267 Some(emitter),
268 false,
269 1,
270 )
271 }
272}
273
274impl Cheatcode for expectEmit_2Call {
275 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
276 let Self {} = self;
277 expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], None, false, 1)
278 }
279}
280
281impl Cheatcode for expectEmit_3Call {
282 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
283 let Self { emitter } = *self;
284 expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], Some(emitter), false, 1)
285 }
286}
287
288impl Cheatcode for expectEmit_4Call {
289 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
290 let Self { checkTopic1, checkTopic2, checkTopic3, checkData, count } = *self;
291 expect_emit(
292 ccx.state,
293 ccx.ecx.journaled_state.depth(),
294 [true, checkTopic1, checkTopic2, checkTopic3, checkData],
295 None,
296 false,
297 count,
298 )
299 }
300}
301
302impl Cheatcode for expectEmit_5Call {
303 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
304 let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter, count } = *self;
305 expect_emit(
306 ccx.state,
307 ccx.ecx.journaled_state.depth(),
308 [true, checkTopic1, checkTopic2, checkTopic3, checkData],
309 Some(emitter),
310 false,
311 count,
312 )
313 }
314}
315
316impl Cheatcode for expectEmit_6Call {
317 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
318 let Self { count } = *self;
319 expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], None, false, count)
320 }
321}
322
323impl Cheatcode for expectEmit_7Call {
324 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
325 let Self { emitter, count } = *self;
326 expect_emit(
327 ccx.state,
328 ccx.ecx.journaled_state.depth(),
329 [true; 5],
330 Some(emitter),
331 false,
332 count,
333 )
334 }
335}
336
337impl Cheatcode for expectEmitAnonymous_0Call {
338 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
339 let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData } = *self;
340 expect_emit(
341 ccx.state,
342 ccx.ecx.journaled_state.depth(),
343 [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],
344 None,
345 true,
346 1,
347 )
348 }
349}
350
351impl Cheatcode for expectEmitAnonymous_1Call {
352 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
353 let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;
354 expect_emit(
355 ccx.state,
356 ccx.ecx.journaled_state.depth(),
357 [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],
358 Some(emitter),
359 true,
360 1,
361 )
362 }
363}
364
365impl Cheatcode for expectEmitAnonymous_2Call {
366 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
367 let Self {} = self;
368 expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], None, true, 1)
369 }
370}
371
372impl Cheatcode for expectEmitAnonymous_3Call {
373 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
374 let Self { emitter } = *self;
375 expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], Some(emitter), true, 1)
376 }
377}
378
379impl Cheatcode for expectCreateCall {
380 fn apply(&self, state: &mut Cheatcodes) -> Result {
381 let Self { bytecode, deployer } = self;
382 expect_create(state, bytecode.clone(), *deployer, CreateScheme::Create)
383 }
384}
385
386impl Cheatcode for expectCreate2Call {
387 fn apply(&self, state: &mut Cheatcodes) -> Result {
388 let Self { bytecode, deployer } = self;
389 expect_create(state, bytecode.clone(), *deployer, CreateScheme::Create2)
390 }
391}
392
393impl Cheatcode for expectRevert_0Call {
394 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
395 let Self {} = self;
396 expect_revert(ccx.state, None, ccx.ecx.journaled_state.depth(), false, false, None, 1)
397 }
398}
399
400impl Cheatcode for expectRevert_1Call {
401 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
402 let Self { revertData } = self;
403 expect_revert(
404 ccx.state,
405 Some(revertData.as_ref()),
406 ccx.ecx.journaled_state.depth(),
407 false,
408 false,
409 None,
410 1,
411 )
412 }
413}
414
415impl Cheatcode for expectRevert_2Call {
416 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
417 let Self { revertData } = self;
418 expect_revert(
419 ccx.state,
420 Some(revertData),
421 ccx.ecx.journaled_state.depth(),
422 false,
423 false,
424 None,
425 1,
426 )
427 }
428}
429
430impl Cheatcode for expectRevert_3Call {
431 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
432 let Self { reverter } = self;
433 expect_revert(
434 ccx.state,
435 None,
436 ccx.ecx.journaled_state.depth(),
437 false,
438 false,
439 Some(*reverter),
440 1,
441 )
442 }
443}
444
445impl Cheatcode for expectRevert_4Call {
446 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
447 let Self { revertData, reverter } = self;
448 expect_revert(
449 ccx.state,
450 Some(revertData.as_ref()),
451 ccx.ecx.journaled_state.depth(),
452 false,
453 false,
454 Some(*reverter),
455 1,
456 )
457 }
458}
459
460impl Cheatcode for expectRevert_5Call {
461 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
462 let Self { revertData, reverter } = self;
463 expect_revert(
464 ccx.state,
465 Some(revertData),
466 ccx.ecx.journaled_state.depth(),
467 false,
468 false,
469 Some(*reverter),
470 1,
471 )
472 }
473}
474
475impl Cheatcode for expectRevert_6Call {
476 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
477 let Self { count } = self;
478 expect_revert(ccx.state, None, ccx.ecx.journaled_state.depth(), false, false, None, *count)
479 }
480}
481
482impl Cheatcode for expectRevert_7Call {
483 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
484 let Self { revertData, count } = self;
485 expect_revert(
486 ccx.state,
487 Some(revertData.as_ref()),
488 ccx.ecx.journaled_state.depth(),
489 false,
490 false,
491 None,
492 *count,
493 )
494 }
495}
496
497impl Cheatcode for expectRevert_8Call {
498 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
499 let Self { revertData, count } = self;
500 expect_revert(
501 ccx.state,
502 Some(revertData),
503 ccx.ecx.journaled_state.depth(),
504 false,
505 false,
506 None,
507 *count,
508 )
509 }
510}
511
512impl Cheatcode for expectRevert_9Call {
513 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
514 let Self { reverter, count } = self;
515 expect_revert(
516 ccx.state,
517 None,
518 ccx.ecx.journaled_state.depth(),
519 false,
520 false,
521 Some(*reverter),
522 *count,
523 )
524 }
525}
526
527impl Cheatcode for expectRevert_10Call {
528 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
529 let Self { revertData, reverter, count } = self;
530 expect_revert(
531 ccx.state,
532 Some(revertData.as_ref()),
533 ccx.ecx.journaled_state.depth(),
534 false,
535 false,
536 Some(*reverter),
537 *count,
538 )
539 }
540}
541
542impl Cheatcode for expectRevert_11Call {
543 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
544 let Self { revertData, reverter, count } = self;
545 expect_revert(
546 ccx.state,
547 Some(revertData),
548 ccx.ecx.journaled_state.depth(),
549 false,
550 false,
551 Some(*reverter),
552 *count,
553 )
554 }
555}
556
557impl Cheatcode for expectPartialRevert_0Call {
558 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
559 let Self { revertData } = self;
560 expect_revert(
561 ccx.state,
562 Some(revertData.as_ref()),
563 ccx.ecx.journaled_state.depth(),
564 false,
565 true,
566 None,
567 1,
568 )
569 }
570}
571
572impl Cheatcode for expectPartialRevert_1Call {
573 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
574 let Self { revertData, reverter } = self;
575 expect_revert(
576 ccx.state,
577 Some(revertData.as_ref()),
578 ccx.ecx.journaled_state.depth(),
579 false,
580 true,
581 Some(*reverter),
582 1,
583 )
584 }
585}
586
587impl Cheatcode for _expectCheatcodeRevert_0Call {
588 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
589 expect_revert(ccx.state, None, ccx.ecx.journaled_state.depth(), true, false, None, 1)
590 }
591}
592
593impl Cheatcode for _expectCheatcodeRevert_1Call {
594 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
595 let Self { revertData } = self;
596 expect_revert(
597 ccx.state,
598 Some(revertData.as_ref()),
599 ccx.ecx.journaled_state.depth(),
600 true,
601 false,
602 None,
603 1,
604 )
605 }
606}
607
608impl Cheatcode for _expectCheatcodeRevert_2Call {
609 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
610 let Self { revertData } = self;
611 expect_revert(
612 ccx.state,
613 Some(revertData),
614 ccx.ecx.journaled_state.depth(),
615 true,
616 false,
617 None,
618 1,
619 )
620 }
621}
622
623impl Cheatcode for expectSafeMemoryCall {
624 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
625 let Self { min, max } = *self;
626 expect_safe_memory(ccx.state, min, max, ccx.ecx.journaled_state.depth())
627 }
628}
629
630impl Cheatcode for stopExpectSafeMemoryCall {
631 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
632 let Self {} = self;
633 ccx.state.allowed_mem_writes.remove(&ccx.ecx.journaled_state.depth());
634 Ok(Default::default())
635 }
636}
637
638impl Cheatcode for expectSafeMemoryCallCall {
639 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
640 let Self { min, max } = *self;
641 expect_safe_memory(ccx.state, min, max, ccx.ecx.journaled_state.depth() + 1)
642 }
643}
644
645impl RevertParameters for ExpectedRevert {
646 fn reverter(&self) -> Option<Address> {
647 self.reverter
648 }
649
650 fn reason(&self) -> Option<&[u8]> {
651 self.reason.as_deref()
652 }
653
654 fn partial_match(&self) -> bool {
655 self.partial_match
656 }
657}
658
659#[expect(clippy::too_many_arguments)] fn expect_call(
677 state: &mut Cheatcodes,
678 target: &Address,
679 calldata: &Bytes,
680 value: Option<&U256>,
681 mut gas: Option<u64>,
682 mut min_gas: Option<u64>,
683 count: u64,
684 call_type: ExpectedCallType,
685) -> Result {
686 let expecteds = state.expected_calls.entry(*target).or_default();
687
688 if let Some(val) = value {
689 if *val > U256::ZERO {
690 let positive_value_cost_stipend = 2300;
693 if let Some(gas) = &mut gas {
694 *gas += positive_value_cost_stipend;
695 }
696 if let Some(min_gas) = &mut min_gas {
697 *min_gas += positive_value_cost_stipend;
698 }
699 }
700 }
701
702 match call_type {
703 ExpectedCallType::Count => {
704 ensure!(
708 !expecteds.contains_key(calldata),
709 "counted expected calls can only bet set once"
710 );
711 expecteds.insert(
712 calldata.clone(),
713 (ExpectedCallData { value: value.copied(), gas, min_gas, count, call_type }, 0),
714 );
715 }
716 ExpectedCallType::NonCount => {
717 match expecteds.entry(calldata.clone()) {
720 Entry::Occupied(mut entry) => {
721 let (expected, _) = entry.get_mut();
722 ensure!(
724 expected.call_type == ExpectedCallType::NonCount,
725 "cannot overwrite a counted expectCall with a non-counted expectCall"
726 );
727 expected.count += 1;
728 }
729 Entry::Vacant(entry) => {
731 entry.insert((
732 ExpectedCallData { value: value.copied(), gas, min_gas, count, call_type },
733 0,
734 ));
735 }
736 }
737 }
738 }
739
740 Ok(Default::default())
741}
742
743fn expect_emit(
744 state: &mut Cheatcodes,
745 depth: u64,
746 checks: [bool; 5],
747 address: Option<Address>,
748 anonymous: bool,
749 count: u64,
750) -> Result {
751 let expected_emit =
752 ExpectedEmit { depth, checks, address, found: false, log: None, anonymous, count };
753 if let Some(found_emit_pos) = state.expected_emits.iter().position(|(emit, _)| emit.found) {
754 state.expected_emits.insert(found_emit_pos, (expected_emit, Default::default()));
757 } else {
758 state.expected_emits.push_back((expected_emit, Default::default()));
760 }
761
762 Ok(Default::default())
763}
764
765pub(crate) fn handle_expect_emit(
766 state: &mut Cheatcodes,
767 log: &alloy_primitives::Log,
768 interpreter: &mut Interpreter,
769) {
770 if state.expected_emits.iter().all(|(expected, _)| expected.found) {
781 return
782 }
783
784 let should_fill_logs = state.expected_emits.iter().any(|(expected, _)| expected.log.is_none());
785 let index_to_fill_or_check = if should_fill_logs {
786 state
789 .expected_emits
790 .iter()
791 .position(|(emit, _)| emit.found)
792 .unwrap_or(state.expected_emits.len())
793 .saturating_sub(1)
794 } else {
795 0
798 };
799
800 let (mut event_to_fill_or_check, mut count_map) = state
801 .expected_emits
802 .remove(index_to_fill_or_check)
803 .expect("we should have an emit to fill or check");
804
805 let Some(expected) = &event_to_fill_or_check.log else {
806 if event_to_fill_or_check.anonymous || !log.topics().is_empty() {
809 event_to_fill_or_check.log = Some(log.data.clone());
810 state
812 .expected_emits
813 .insert(index_to_fill_or_check, (event_to_fill_or_check, count_map));
814 } else {
815 interpreter.instruction_result = InstructionResult::Revert;
816 interpreter.next_action = InterpreterAction::Return {
817 result: InterpreterResult {
818 output: Error::encode("use vm.expectEmitAnonymous to match anonymous events"),
819 gas: interpreter.gas,
820 result: InstructionResult::Revert,
821 },
822 };
823 }
824 return
825 };
826
827 match count_map.entry(log.address) {
829 Entry::Occupied(mut entry) => {
830 let log_count_map = entry.get_mut();
833 log_count_map.insert(&log.data);
834 }
835 Entry::Vacant(entry) => {
836 let mut log_count_map = LogCountMap::new(&event_to_fill_or_check);
837
838 if log_count_map.satisfies_checks(&log.data) {
839 log_count_map.insert(&log.data);
840
841 entry.insert(log_count_map);
843 }
844 }
845 }
846
847 event_to_fill_or_check.found = || -> bool {
848 if !checks_topics_and_data(event_to_fill_or_check.checks, expected, log) {
849 return false
850 }
851
852 if event_to_fill_or_check.address.is_some_and(|addr| addr != log.address) {
854 return false;
855 }
856
857 let expected_count = event_to_fill_or_check.count;
858
859 match event_to_fill_or_check.address {
860 Some(emitter) => count_map
861 .get(&emitter)
862 .is_some_and(|log_map| log_map.count(&log.data) >= expected_count),
863 None => count_map
864 .values()
865 .find(|log_map| log_map.satisfies_checks(&log.data))
866 .is_some_and(|map| map.count(&log.data) >= expected_count),
867 }
868 }();
869
870 if event_to_fill_or_check.found {
873 state.expected_emits.push_back((event_to_fill_or_check, count_map));
874 } else {
875 state.expected_emits.push_front((event_to_fill_or_check, count_map));
878 }
879}
880
881pub type ExpectedEmitTracker = VecDeque<(ExpectedEmit, AddressHashMap<LogCountMap>)>;
886
887#[derive(Clone, Debug, Default)]
888pub struct LogCountMap {
889 checks: [bool; 5],
890 expected_log: RawLog,
891 map: HashMap<RawLog, u64>,
892}
893
894impl LogCountMap {
895 fn new(expected_emit: &ExpectedEmit) -> Self {
897 Self {
898 checks: expected_emit.checks,
899 expected_log: expected_emit.log.clone().expect("log should be filled here"),
900 map: Default::default(),
901 }
902 }
903
904 fn insert(&mut self, log: &RawLog) -> bool {
910 if self.map.contains_key(log) {
912 self.map.entry(log.clone()).and_modify(|c| *c += 1);
913
914 return true
915 }
916
917 if !self.satisfies_checks(log) {
918 return false
919 }
920
921 self.map.entry(log.clone()).and_modify(|c| *c += 1).or_insert(1);
922
923 true
924 }
925
926 fn satisfies_checks(&self, log: &RawLog) -> bool {
928 checks_topics_and_data(self.checks, &self.expected_log, log)
929 }
930
931 pub fn count(&self, log: &RawLog) -> u64 {
932 if !self.satisfies_checks(log) {
933 return 0
934 }
935
936 self.count_unchecked()
937 }
938
939 pub fn count_unchecked(&self) -> u64 {
940 self.map.values().sum()
941 }
942}
943
944fn expect_create(
945 state: &mut Cheatcodes,
946 bytecode: Bytes,
947 deployer: Address,
948 create_scheme: CreateScheme,
949) -> Result {
950 let expected_create = ExpectedCreate { bytecode, deployer, create_scheme };
951 state.expected_creates.push(expected_create);
952
953 Ok(Default::default())
954}
955
956fn expect_revert(
957 state: &mut Cheatcodes,
958 reason: Option<&[u8]>,
959 depth: u64,
960 cheatcode: bool,
961 partial_match: bool,
962 reverter: Option<Address>,
963 count: u64,
964) -> Result {
965 ensure!(
966 state.expected_revert.is_none(),
967 "you must call another function prior to expecting a second revert"
968 );
969 state.expected_revert = Some(ExpectedRevert {
970 reason: reason.map(<[_]>::to_vec),
971 depth,
972 kind: if cheatcode {
973 ExpectedRevertKind::Cheatcode { pending_processing: true }
974 } else {
975 ExpectedRevertKind::Default
976 },
977 partial_match,
978 reverter,
979 reverted_by: None,
980 max_depth: depth,
981 count,
982 actual_count: 0,
983 });
984 Ok(Default::default())
985}
986
987fn checks_topics_and_data(checks: [bool; 5], expected: &RawLog, log: &RawLog) -> bool {
988 if log.topics().len() != expected.topics().len() {
989 return false
990 }
991
992 if !log
994 .topics()
995 .iter()
996 .enumerate()
997 .filter(|(i, _)| checks[*i])
998 .all(|(i, topic)| topic == &expected.topics()[i])
999 {
1000 return false
1001 }
1002
1003 if checks[4] && expected.data.as_ref() != log.data.as_ref() {
1005 return false
1006 }
1007
1008 true
1009}
1010
1011fn expect_safe_memory(state: &mut Cheatcodes, start: u64, end: u64, depth: u64) -> Result {
1012 ensure!(start < end, "memory range start ({start}) is greater than end ({end})");
1013 #[expect(clippy::single_range_in_vec_init)] let offsets = state.allowed_mem_writes.entry(depth).or_insert_with(|| vec![0..0x60]);
1015 offsets.push(start..end);
1016 Ok(Default::default())
1017}