foundry_cheatcodes/test/
expect.rs

1use std::{
2    collections::VecDeque,
3    fmt::{self, Display},
4};
5
6use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Error, Result, Vm::*};
7use alloy_dyn_abi::{DynSolValue, EventExt};
8use alloy_json_abi::Event;
9use alloy_primitives::{
10    Address, Bytes, LogData as RawLog, U256, hex,
11    map::{AddressHashMap, HashMap, hash_map::Entry},
12};
13use foundry_common::{abi::get_indexed_event, fmt::format_token};
14use foundry_evm_traces::DecodedCallLog;
15use revm::{
16    context::JournalTr,
17    interpreter::{
18        InstructionResult, Interpreter, InterpreterAction, interpreter_types::LoopControl,
19    },
20};
21
22use super::revert_handlers::RevertParameters;
23/// Tracks the expected calls per address.
24///
25/// For each address, we track the expected calls per call data. We track it in such manner
26/// so that we don't mix together calldatas that only contain selectors and calldatas that contain
27/// selector and arguments (partial and full matches).
28///
29/// This then allows us to customize the matching behavior for each call data on the
30/// `ExpectedCallData` struct and track how many times we've actually seen the call on the second
31/// element of the tuple.
32pub type ExpectedCallTracker = HashMap<Address, HashMap<Bytes, (ExpectedCallData, u64)>>;
33
34#[derive(Clone, Debug)]
35pub struct ExpectedCallData {
36    /// The expected value sent in the call
37    pub value: Option<U256>,
38    /// The expected gas supplied to the call
39    pub gas: Option<u64>,
40    /// The expected *minimum* gas supplied to the call
41    pub min_gas: Option<u64>,
42    /// The number of times the call is expected to be made.
43    /// If the type of call is `NonCount`, this is the lower bound for the number of calls
44    /// that must be seen.
45    /// If the type of call is `Count`, this is the exact number of calls that must be seen.
46    pub count: u64,
47    /// The type of expected call.
48    pub call_type: ExpectedCallType,
49}
50
51/// The type of expected call.
52#[derive(Clone, Debug, PartialEq, Eq)]
53pub enum ExpectedCallType {
54    /// The call is expected to be made at least once.
55    NonCount,
56    /// The exact number of calls expected.
57    Count,
58}
59
60/// The type of expected revert.
61#[derive(Clone, Debug)]
62pub enum ExpectedRevertKind {
63    /// Expects revert from the next non-cheatcode call.
64    Default,
65    /// Expects revert from the next cheatcode call.
66    ///
67    /// The `pending_processing` flag is used to track whether we have exited
68    /// `expectCheatcodeRevert` context or not.
69    /// We have to track it to avoid expecting `expectCheatcodeRevert` call to revert itself.
70    Cheatcode { pending_processing: bool },
71}
72
73#[derive(Clone, Debug)]
74pub struct ExpectedRevert {
75    /// The expected data returned by the revert, None being any.
76    pub reason: Option<Bytes>,
77    /// The depth at which the revert is expected.
78    pub depth: usize,
79    /// The type of expected revert.
80    pub kind: ExpectedRevertKind,
81    /// If true then only the first 4 bytes of expected data returned by the revert are checked.
82    pub partial_match: bool,
83    /// Contract expected to revert next call.
84    pub reverter: Option<Address>,
85    /// Address that reverted the call.
86    pub reverted_by: Option<Address>,
87    /// Max call depth reached during next call execution.
88    pub max_depth: usize,
89    /// Number of times this revert is expected.
90    pub count: u64,
91    /// Actual number of times this revert has been seen.
92    pub actual_count: u64,
93}
94
95#[derive(Clone, Debug)]
96pub struct ExpectedEmit {
97    /// The depth at which we expect this emit to have occurred
98    pub depth: usize,
99    /// The log we expect
100    pub log: Option<RawLog>,
101    /// The checks to perform:
102    /// ```text
103    /// ┌───────┬───────┬───────┬───────┬────┐
104    /// │topic 0│topic 1│topic 2│topic 3│data│
105    /// └───────┴───────┴───────┴───────┴────┘
106    /// ```
107    pub checks: [bool; 5],
108    /// If present, check originating address against this
109    pub address: Option<Address>,
110    /// If present, relax the requirement that topic 0 must be present. This allows anonymous
111    /// events with no indexed topics to be matched.
112    pub anonymous: bool,
113    /// Whether the log was actually found in the subcalls
114    pub found: bool,
115    /// Number of times the log is expected to be emitted
116    pub count: u64,
117    /// Stores mismatch details if a log didn't match
118    pub mismatch_error: Option<String>,
119}
120
121#[derive(Clone, Debug)]
122pub struct ExpectedCreate {
123    /// The address that deployed the contract
124    pub deployer: Address,
125    /// Runtime bytecode of the contract
126    pub bytecode: Bytes,
127    /// Whether deployed with CREATE or CREATE2
128    pub create_scheme: CreateScheme,
129}
130
131#[derive(Clone, Debug)]
132pub enum CreateScheme {
133    Create,
134    Create2,
135}
136
137impl Display for CreateScheme {
138    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
139        match self {
140            Self::Create => write!(f, "CREATE"),
141            Self::Create2 => write!(f, "CREATE2"),
142        }
143    }
144}
145
146impl From<revm::context_interface::CreateScheme> for CreateScheme {
147    fn from(scheme: revm::context_interface::CreateScheme) -> Self {
148        match scheme {
149            revm::context_interface::CreateScheme::Create => Self::Create,
150            revm::context_interface::CreateScheme::Create2 { .. } => Self::Create2,
151            _ => unimplemented!("Unsupported create scheme"),
152        }
153    }
154}
155
156impl CreateScheme {
157    pub fn eq(&self, create_scheme: Self) -> bool {
158        matches!(
159            (self, create_scheme),
160            (Self::Create, Self::Create) | (Self::Create2, Self::Create2 { .. })
161        )
162    }
163}
164
165impl Cheatcode for expectCall_0Call {
166    fn apply(&self, state: &mut Cheatcodes) -> Result {
167        let Self { callee, data } = self;
168        expect_call(state, callee, data, None, None, None, 1, ExpectedCallType::NonCount)
169    }
170}
171
172impl Cheatcode for expectCall_1Call {
173    fn apply(&self, state: &mut Cheatcodes) -> Result {
174        let Self { callee, data, count } = self;
175        expect_call(state, callee, data, None, None, None, *count, ExpectedCallType::Count)
176    }
177}
178
179impl Cheatcode for expectCall_2Call {
180    fn apply(&self, state: &mut Cheatcodes) -> Result {
181        let Self { callee, msgValue, data } = self;
182        expect_call(state, callee, data, Some(msgValue), None, None, 1, ExpectedCallType::NonCount)
183    }
184}
185
186impl Cheatcode for expectCall_3Call {
187    fn apply(&self, state: &mut Cheatcodes) -> Result {
188        let Self { callee, msgValue, data, count } = self;
189        expect_call(
190            state,
191            callee,
192            data,
193            Some(msgValue),
194            None,
195            None,
196            *count,
197            ExpectedCallType::Count,
198        )
199    }
200}
201
202impl Cheatcode for expectCall_4Call {
203    fn apply(&self, state: &mut Cheatcodes) -> Result {
204        let Self { callee, msgValue, gas, data } = self;
205        expect_call(
206            state,
207            callee,
208            data,
209            Some(msgValue),
210            Some(*gas),
211            None,
212            1,
213            ExpectedCallType::NonCount,
214        )
215    }
216}
217
218impl Cheatcode for expectCall_5Call {
219    fn apply(&self, state: &mut Cheatcodes) -> Result {
220        let Self { callee, msgValue, gas, data, count } = self;
221        expect_call(
222            state,
223            callee,
224            data,
225            Some(msgValue),
226            Some(*gas),
227            None,
228            *count,
229            ExpectedCallType::Count,
230        )
231    }
232}
233
234impl Cheatcode for expectCallMinGas_0Call {
235    fn apply(&self, state: &mut Cheatcodes) -> Result {
236        let Self { callee, msgValue, minGas, data } = self;
237        expect_call(
238            state,
239            callee,
240            data,
241            Some(msgValue),
242            None,
243            Some(*minGas),
244            1,
245            ExpectedCallType::NonCount,
246        )
247    }
248}
249
250impl Cheatcode for expectCallMinGas_1Call {
251    fn apply(&self, state: &mut Cheatcodes) -> Result {
252        let Self { callee, msgValue, minGas, data, count } = self;
253        expect_call(
254            state,
255            callee,
256            data,
257            Some(msgValue),
258            None,
259            Some(*minGas),
260            *count,
261            ExpectedCallType::Count,
262        )
263    }
264}
265
266impl Cheatcode for expectEmit_0Call {
267    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
268        let Self { checkTopic1, checkTopic2, checkTopic3, checkData } = *self;
269        expect_emit(
270            ccx.state,
271            ccx.ecx.journaled_state.depth(),
272            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
273            None,
274            false,
275            1,
276        )
277    }
278}
279
280impl Cheatcode for expectEmit_1Call {
281    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
282        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;
283        expect_emit(
284            ccx.state,
285            ccx.ecx.journaled_state.depth(),
286            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
287            Some(emitter),
288            false,
289            1,
290        )
291    }
292}
293
294impl Cheatcode for expectEmit_2Call {
295    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
296        let Self {} = self;
297        expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], None, false, 1)
298    }
299}
300
301impl Cheatcode for expectEmit_3Call {
302    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
303        let Self { emitter } = *self;
304        expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], Some(emitter), false, 1)
305    }
306}
307
308impl Cheatcode for expectEmit_4Call {
309    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
310        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, count } = *self;
311        expect_emit(
312            ccx.state,
313            ccx.ecx.journaled_state.depth(),
314            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
315            None,
316            false,
317            count,
318        )
319    }
320}
321
322impl Cheatcode for expectEmit_5Call {
323    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
324        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter, count } = *self;
325        expect_emit(
326            ccx.state,
327            ccx.ecx.journaled_state.depth(),
328            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
329            Some(emitter),
330            false,
331            count,
332        )
333    }
334}
335
336impl Cheatcode for expectEmit_6Call {
337    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
338        let Self { count } = *self;
339        expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], None, false, count)
340    }
341}
342
343impl Cheatcode for expectEmit_7Call {
344    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
345        let Self { emitter, count } = *self;
346        expect_emit(
347            ccx.state,
348            ccx.ecx.journaled_state.depth(),
349            [true; 5],
350            Some(emitter),
351            false,
352            count,
353        )
354    }
355}
356
357impl Cheatcode for expectEmitAnonymous_0Call {
358    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
359        let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData } = *self;
360        expect_emit(
361            ccx.state,
362            ccx.ecx.journaled_state.depth(),
363            [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],
364            None,
365            true,
366            1,
367        )
368    }
369}
370
371impl Cheatcode for expectEmitAnonymous_1Call {
372    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
373        let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;
374        expect_emit(
375            ccx.state,
376            ccx.ecx.journaled_state.depth(),
377            [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],
378            Some(emitter),
379            true,
380            1,
381        )
382    }
383}
384
385impl Cheatcode for expectEmitAnonymous_2Call {
386    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
387        let Self {} = self;
388        expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], None, true, 1)
389    }
390}
391
392impl Cheatcode for expectEmitAnonymous_3Call {
393    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
394        let Self { emitter } = *self;
395        expect_emit(ccx.state, ccx.ecx.journaled_state.depth(), [true; 5], Some(emitter), true, 1)
396    }
397}
398
399impl Cheatcode for expectCreateCall {
400    fn apply(&self, state: &mut Cheatcodes) -> Result {
401        let Self { bytecode, deployer } = self;
402        expect_create(state, bytecode.clone(), *deployer, CreateScheme::Create)
403    }
404}
405
406impl Cheatcode for expectCreate2Call {
407    fn apply(&self, state: &mut Cheatcodes) -> Result {
408        let Self { bytecode, deployer } = self;
409        expect_create(state, bytecode.clone(), *deployer, CreateScheme::Create2)
410    }
411}
412
413impl Cheatcode for expectRevert_0Call {
414    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
415        let Self {} = self;
416        expect_revert(ccx.state, None, ccx.ecx.journaled_state.depth(), false, false, None, 1)
417    }
418}
419
420impl Cheatcode for expectRevert_1Call {
421    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
422        let Self { revertData } = self;
423        expect_revert(
424            ccx.state,
425            Some(revertData.as_ref()),
426            ccx.ecx.journaled_state.depth(),
427            false,
428            false,
429            None,
430            1,
431        )
432    }
433}
434
435impl Cheatcode for expectRevert_2Call {
436    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
437        let Self { revertData } = self;
438        expect_revert(
439            ccx.state,
440            Some(revertData),
441            ccx.ecx.journaled_state.depth(),
442            false,
443            false,
444            None,
445            1,
446        )
447    }
448}
449
450impl Cheatcode for expectRevert_3Call {
451    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
452        let Self { reverter } = self;
453        expect_revert(
454            ccx.state,
455            None,
456            ccx.ecx.journaled_state.depth(),
457            false,
458            false,
459            Some(*reverter),
460            1,
461        )
462    }
463}
464
465impl Cheatcode for expectRevert_4Call {
466    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
467        let Self { revertData, reverter } = self;
468        expect_revert(
469            ccx.state,
470            Some(revertData.as_ref()),
471            ccx.ecx.journaled_state.depth(),
472            false,
473            false,
474            Some(*reverter),
475            1,
476        )
477    }
478}
479
480impl Cheatcode for expectRevert_5Call {
481    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
482        let Self { revertData, reverter } = self;
483        expect_revert(
484            ccx.state,
485            Some(revertData),
486            ccx.ecx.journaled_state.depth(),
487            false,
488            false,
489            Some(*reverter),
490            1,
491        )
492    }
493}
494
495impl Cheatcode for expectRevert_6Call {
496    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
497        let Self { count } = self;
498        expect_revert(ccx.state, None, ccx.ecx.journaled_state.depth(), false, false, None, *count)
499    }
500}
501
502impl Cheatcode for expectRevert_7Call {
503    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
504        let Self { revertData, count } = self;
505        expect_revert(
506            ccx.state,
507            Some(revertData.as_ref()),
508            ccx.ecx.journaled_state.depth(),
509            false,
510            false,
511            None,
512            *count,
513        )
514    }
515}
516
517impl Cheatcode for expectRevert_8Call {
518    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
519        let Self { revertData, count } = self;
520        expect_revert(
521            ccx.state,
522            Some(revertData),
523            ccx.ecx.journaled_state.depth(),
524            false,
525            false,
526            None,
527            *count,
528        )
529    }
530}
531
532impl Cheatcode for expectRevert_9Call {
533    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
534        let Self { reverter, count } = self;
535        expect_revert(
536            ccx.state,
537            None,
538            ccx.ecx.journaled_state.depth(),
539            false,
540            false,
541            Some(*reverter),
542            *count,
543        )
544    }
545}
546
547impl Cheatcode for expectRevert_10Call {
548    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
549        let Self { revertData, reverter, count } = self;
550        expect_revert(
551            ccx.state,
552            Some(revertData.as_ref()),
553            ccx.ecx.journaled_state.depth(),
554            false,
555            false,
556            Some(*reverter),
557            *count,
558        )
559    }
560}
561
562impl Cheatcode for expectRevert_11Call {
563    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
564        let Self { revertData, reverter, count } = self;
565        expect_revert(
566            ccx.state,
567            Some(revertData),
568            ccx.ecx.journaled_state.depth(),
569            false,
570            false,
571            Some(*reverter),
572            *count,
573        )
574    }
575}
576
577impl Cheatcode for expectPartialRevert_0Call {
578    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
579        let Self { revertData } = self;
580        expect_revert(
581            ccx.state,
582            Some(revertData.as_ref()),
583            ccx.ecx.journaled_state.depth(),
584            false,
585            true,
586            None,
587            1,
588        )
589    }
590}
591
592impl Cheatcode for expectPartialRevert_1Call {
593    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
594        let Self { revertData, reverter } = self;
595        expect_revert(
596            ccx.state,
597            Some(revertData.as_ref()),
598            ccx.ecx.journaled_state.depth(),
599            false,
600            true,
601            Some(*reverter),
602            1,
603        )
604    }
605}
606
607impl Cheatcode for _expectCheatcodeRevert_0Call {
608    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
609        expect_revert(ccx.state, None, ccx.ecx.journaled_state.depth(), true, false, None, 1)
610    }
611}
612
613impl Cheatcode for _expectCheatcodeRevert_1Call {
614    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
615        let Self { revertData } = self;
616        expect_revert(
617            ccx.state,
618            Some(revertData.as_ref()),
619            ccx.ecx.journaled_state.depth(),
620            true,
621            false,
622            None,
623            1,
624        )
625    }
626}
627
628impl Cheatcode for _expectCheatcodeRevert_2Call {
629    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
630        let Self { revertData } = self;
631        expect_revert(
632            ccx.state,
633            Some(revertData),
634            ccx.ecx.journaled_state.depth(),
635            true,
636            false,
637            None,
638            1,
639        )
640    }
641}
642
643impl Cheatcode for expectSafeMemoryCall {
644    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
645        let Self { min, max } = *self;
646        expect_safe_memory(ccx.state, min, max, ccx.ecx.journaled_state.depth().try_into()?)
647    }
648}
649
650impl Cheatcode for stopExpectSafeMemoryCall {
651    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
652        let Self {} = self;
653        ccx.state.allowed_mem_writes.remove(&ccx.ecx.journaled_state.depth().try_into()?);
654        Ok(Default::default())
655    }
656}
657
658impl Cheatcode for expectSafeMemoryCallCall {
659    fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
660        let Self { min, max } = *self;
661        expect_safe_memory(ccx.state, min, max, (ccx.ecx.journaled_state.depth() + 1).try_into()?)
662    }
663}
664
665impl RevertParameters for ExpectedRevert {
666    fn reverter(&self) -> Option<Address> {
667        self.reverter
668    }
669
670    fn reason(&self) -> Option<&[u8]> {
671        self.reason.as_ref().map(|b| &***b)
672    }
673
674    fn partial_match(&self) -> bool {
675        self.partial_match
676    }
677}
678
679/// Handles expected calls specified by the `expectCall` cheatcodes.
680///
681/// It can handle calls in two ways:
682/// - If the cheatcode was used with a `count` argument, it will expect the call to be made exactly
683///   `count` times. e.g. `vm.expectCall(address(0xc4f3), abi.encodeWithSelector(0xd34db33f), 4)`
684///   will expect the call to address(0xc4f3) with selector `0xd34db33f` to be made exactly 4 times.
685///   If the amount of calls is less or more than 4, the test will fail. Note that the `count`
686///   argument cannot be overwritten with another `vm.expectCall`. If this is attempted,
687///   `expectCall` will revert.
688/// - If the cheatcode was used without a `count` argument, it will expect the call to be made at
689///   least the amount of times the cheatcode was called. This means that `vm.expectCall` without a
690///   count argument can be called many times, but cannot be called with a `count` argument after it
691///   was called without one. If the latter happens, `expectCall` will revert. e.g
692///   `vm.expectCall(address(0xc4f3), abi.encodeWithSelector(0xd34db33f))` will expect the call to
693///   address(0xc4f3) and selector `0xd34db33f` to be made at least once. If the amount of calls is
694///   0, the test will fail. If the call is made more than once, the test will pass.
695#[expect(clippy::too_many_arguments)] // It is what it is
696fn expect_call(
697    state: &mut Cheatcodes,
698    target: &Address,
699    calldata: &Bytes,
700    value: Option<&U256>,
701    mut gas: Option<u64>,
702    mut min_gas: Option<u64>,
703    count: u64,
704    call_type: ExpectedCallType,
705) -> Result {
706    let expecteds = state.expected_calls.entry(*target).or_default();
707
708    if let Some(val) = value
709        && *val > U256::ZERO
710    {
711        // If the value of the transaction is non-zero, the EVM adds a call stipend of 2300 gas
712        // to ensure that the basic fallback function can be called.
713        let positive_value_cost_stipend = 2300;
714        if let Some(gas) = &mut gas {
715            *gas += positive_value_cost_stipend;
716        }
717        if let Some(min_gas) = &mut min_gas {
718            *min_gas += positive_value_cost_stipend;
719        }
720    }
721
722    match call_type {
723        ExpectedCallType::Count => {
724            // Get the expected calls for this target.
725            // In this case, as we're using counted expectCalls, we should not be able to set them
726            // more than once.
727            ensure!(
728                !expecteds.contains_key(calldata),
729                "counted expected calls can only bet set once"
730            );
731            expecteds.insert(
732                calldata.clone(),
733                (ExpectedCallData { value: value.copied(), gas, min_gas, count, call_type }, 0),
734            );
735        }
736        ExpectedCallType::NonCount => {
737            // Check if the expected calldata exists.
738            // If it does, increment the count by one as we expect to see it one more time.
739            match expecteds.entry(calldata.clone()) {
740                Entry::Occupied(mut entry) => {
741                    let (expected, _) = entry.get_mut();
742                    // Ensure we're not overwriting a counted expectCall.
743                    ensure!(
744                        expected.call_type == ExpectedCallType::NonCount,
745                        "cannot overwrite a counted expectCall with a non-counted expectCall"
746                    );
747                    expected.count += 1;
748                }
749                // If it does not exist, then create it.
750                Entry::Vacant(entry) => {
751                    entry.insert((
752                        ExpectedCallData { value: value.copied(), gas, min_gas, count, call_type },
753                        0,
754                    ));
755                }
756            }
757        }
758    }
759
760    Ok(Default::default())
761}
762
763fn expect_emit(
764    state: &mut Cheatcodes,
765    depth: usize,
766    checks: [bool; 5],
767    address: Option<Address>,
768    anonymous: bool,
769    count: u64,
770) -> Result {
771    let expected_emit = ExpectedEmit {
772        depth,
773        checks,
774        address,
775        found: false,
776        log: None,
777        anonymous,
778        count,
779        mismatch_error: None,
780    };
781    if let Some(found_emit_pos) = state.expected_emits.iter().position(|(emit, _)| emit.found) {
782        // The order of emits already found (back of queue) should not be modified, hence push any
783        // new emit before first found emit.
784        state.expected_emits.insert(found_emit_pos, (expected_emit, Default::default()));
785    } else {
786        // If no expected emits then push new one at the back of queue.
787        state.expected_emits.push_back((expected_emit, Default::default()));
788    }
789
790    Ok(Default::default())
791}
792
793pub(crate) fn handle_expect_emit(
794    state: &mut Cheatcodes,
795    log: &alloy_primitives::Log,
796    mut interpreter: Option<&mut Interpreter>,
797) -> Option<&'static str> {
798    // This function returns an optional string indicating a failure reason.
799    // If the string is `Some`, it indicates that the expectation failed with the provided reason.
800    let mut should_fail = None;
801
802    // Fill or check the expected emits.
803    // We expect for emit checks to be filled as they're declared (from oldest to newest),
804    // so we fill them and push them to the back of the queue.
805    // If the user has properly filled all the emits, they'll end up in their original order.
806    // If not, the queue will not be in the order the events will be intended to be filled,
807    // and we'll be able to later detect this and bail.
808
809    // First, we can return early if all events have been matched.
810    // This allows a contract to arbitrarily emit more events than expected (additive behavior),
811    // as long as all the previous events were matched in the order they were expected to be.
812    if state.expected_emits.iter().all(|(expected, _)| expected.found) {
813        return should_fail;
814    }
815
816    // Check count=0 expectations against this log - fail immediately if violated
817    for (expected_emit, _) in &state.expected_emits {
818        if expected_emit.count == 0
819            && !expected_emit.found
820            && let Some(expected_log) = &expected_emit.log
821            && checks_topics_and_data(expected_emit.checks, expected_log, log)
822            // Check revert address 
823            && (expected_emit.address.is_none() || expected_emit.address == Some(log.address))
824        {
825            if let Some(interpreter) = &mut interpreter {
826                // This event was emitted but we expected it NOT to be (count=0)
827                // Fail immediately
828                interpreter.bytecode.set_action(InterpreterAction::new_return(
829                    InstructionResult::Revert,
830                    Error::encode("log emitted but expected 0 times"),
831                    interpreter.gas,
832                ));
833            } else {
834                should_fail = Some("log emitted but expected 0 times");
835            }
836
837            return should_fail;
838        }
839    }
840
841    let should_fill_logs = state.expected_emits.iter().any(|(expected, _)| expected.log.is_none());
842    let index_to_fill_or_check = if should_fill_logs {
843        // If there's anything to fill, we start with the last event to match in the queue
844        // (without taking into account events already matched).
845        state
846            .expected_emits
847            .iter()
848            .position(|(emit, _)| emit.found)
849            .unwrap_or(state.expected_emits.len())
850            .saturating_sub(1)
851    } else {
852        // if all expected logs are filled, check any unmatched event
853        // in the declared order, so we start from the front (like a queue).
854        // Skip count=0 expectations as they are handled separately above
855        state.expected_emits.iter().position(|(emit, _)| !emit.found && emit.count > 0).unwrap_or(0)
856    };
857
858    // If there are only count=0 expectations left, we can return early
859    if !should_fill_logs
860        && state.expected_emits.iter().all(|(emit, _)| emit.found || emit.count == 0)
861    {
862        return should_fail;
863    }
864
865    let (mut event_to_fill_or_check, mut count_map) = state
866        .expected_emits
867        .remove(index_to_fill_or_check)
868        .expect("we should have an emit to fill or check");
869
870    let Some(expected) = &event_to_fill_or_check.log else {
871        // Unless the caller is trying to match an anonymous event, the first topic must be
872        // filled.
873        if event_to_fill_or_check.anonymous || !log.topics().is_empty() {
874            event_to_fill_or_check.log = Some(log.data.clone());
875            // If we only filled the expected log then we put it back at the same position.
876            state
877                .expected_emits
878                .insert(index_to_fill_or_check, (event_to_fill_or_check, count_map));
879        } else if let Some(interpreter) = &mut interpreter {
880            interpreter.bytecode.set_action(InterpreterAction::new_return(
881                InstructionResult::Revert,
882                Error::encode("use vm.expectEmitAnonymous to match anonymous events"),
883                interpreter.gas,
884            ));
885        } else {
886            should_fail = Some("use vm.expectEmitAnonymous to match anonymous events");
887        }
888
889        return should_fail;
890    };
891
892    // Increment/set `count` for `log.address` and `log.data`
893    match count_map.entry(log.address) {
894        Entry::Occupied(mut entry) => {
895            let log_count_map = entry.get_mut();
896            log_count_map.insert(&log.data);
897        }
898        Entry::Vacant(entry) => {
899            let mut log_count_map = LogCountMap::new(&event_to_fill_or_check);
900            if log_count_map.satisfies_checks(&log.data) {
901                log_count_map.insert(&log.data);
902                entry.insert(log_count_map);
903            }
904        }
905    }
906
907    event_to_fill_or_check.found = || -> bool {
908        if !checks_topics_and_data(event_to_fill_or_check.checks, expected, log) {
909            // Store detailed mismatch information
910
911            // Try to decode the events if we have a signature identifier
912            let (expected_decoded, actual_decoded) = if let Some(signatures_identifier) =
913                state.signatures_identifier()
914                && !event_to_fill_or_check.anonymous
915            {
916                (
917                    decode_event(signatures_identifier, expected),
918                    decode_event(signatures_identifier, log),
919                )
920            } else {
921                (None, None)
922            };
923            event_to_fill_or_check.mismatch_error = Some(get_emit_mismatch_message(
924                event_to_fill_or_check.checks,
925                expected,
926                log,
927                event_to_fill_or_check.anonymous,
928                expected_decoded.as_ref(),
929                actual_decoded.as_ref(),
930            ));
931            return false;
932        }
933
934        // Maybe match source address.
935        if event_to_fill_or_check
936            .address
937            .is_some_and(|addr| addr.to_checksum(None) != log.address.to_checksum(None))
938        {
939            event_to_fill_or_check.mismatch_error = Some(format!(
940                "log emitter mismatch: expected={:#x}, got={:#x}",
941                event_to_fill_or_check.address.unwrap(),
942                log.address
943            ));
944            return false;
945        }
946
947        let expected_count = event_to_fill_or_check.count;
948        match event_to_fill_or_check.address {
949            Some(emitter) => count_map
950                .get(&emitter)
951                .is_some_and(|log_map| log_map.count(&log.data) >= expected_count),
952            None => count_map
953                .values()
954                .find(|log_map| log_map.satisfies_checks(&log.data))
955                .is_some_and(|map| map.count(&log.data) >= expected_count),
956        }
957    }();
958
959    // If we found the event, we can push it to the back of the queue
960    // and begin expecting the next event.
961    if event_to_fill_or_check.found {
962        state.expected_emits.push_back((event_to_fill_or_check, count_map));
963    } else {
964        // We did not match this event, so we need to keep waiting for the right one to
965        // appear.
966        state.expected_emits.push_front((event_to_fill_or_check, count_map));
967    }
968
969    should_fail
970}
971
972/// Handles expected emits specified by the `expectEmit` cheatcodes.
973///
974/// The second element of the tuple counts the number of times the log has been emitted by a
975/// particular address
976pub type ExpectedEmitTracker = VecDeque<(ExpectedEmit, AddressHashMap<LogCountMap>)>;
977
978#[derive(Clone, Debug, Default)]
979pub struct LogCountMap {
980    checks: [bool; 5],
981    expected_log: RawLog,
982    map: HashMap<RawLog, u64>,
983}
984
985impl LogCountMap {
986    /// Instantiates `LogCountMap`.
987    fn new(expected_emit: &ExpectedEmit) -> Self {
988        Self {
989            checks: expected_emit.checks,
990            expected_log: expected_emit.log.clone().expect("log should be filled here"),
991            map: Default::default(),
992        }
993    }
994
995    /// Inserts a log into the map and increments the count.
996    ///
997    /// The log must pass all checks against the expected log for the count to increment.
998    ///
999    /// Returns true if the log was inserted and count was incremented.
1000    fn insert(&mut self, log: &RawLog) -> bool {
1001        // If its already in the map, increment the count without checking.
1002        if self.map.contains_key(log) {
1003            self.map.entry(log.clone()).and_modify(|c| *c += 1);
1004
1005            return true;
1006        }
1007
1008        if !self.satisfies_checks(log) {
1009            return false;
1010        }
1011
1012        self.map.entry(log.clone()).and_modify(|c| *c += 1).or_insert(1);
1013
1014        true
1015    }
1016
1017    /// Checks the incoming raw log against the expected logs topics and data.
1018    fn satisfies_checks(&self, log: &RawLog) -> bool {
1019        checks_topics_and_data(self.checks, &self.expected_log, log)
1020    }
1021
1022    pub fn count(&self, log: &RawLog) -> u64 {
1023        if !self.satisfies_checks(log) {
1024            return 0;
1025        }
1026
1027        self.count_unchecked()
1028    }
1029
1030    pub fn count_unchecked(&self) -> u64 {
1031        self.map.values().sum()
1032    }
1033}
1034
1035fn expect_create(
1036    state: &mut Cheatcodes,
1037    bytecode: Bytes,
1038    deployer: Address,
1039    create_scheme: CreateScheme,
1040) -> Result {
1041    let expected_create = ExpectedCreate { bytecode, deployer, create_scheme };
1042    state.expected_creates.push(expected_create);
1043
1044    Ok(Default::default())
1045}
1046
1047fn expect_revert(
1048    state: &mut Cheatcodes,
1049    reason: Option<&[u8]>,
1050    depth: usize,
1051    cheatcode: bool,
1052    partial_match: bool,
1053    reverter: Option<Address>,
1054    count: u64,
1055) -> Result {
1056    ensure!(
1057        state.expected_revert.is_none(),
1058        "you must call another function prior to expecting a second revert"
1059    );
1060    state.expected_revert = Some(ExpectedRevert {
1061        reason: reason.map(Bytes::copy_from_slice),
1062        depth,
1063        kind: if cheatcode {
1064            ExpectedRevertKind::Cheatcode { pending_processing: true }
1065        } else {
1066            ExpectedRevertKind::Default
1067        },
1068        partial_match,
1069        reverter,
1070        reverted_by: None,
1071        max_depth: depth,
1072        count,
1073        actual_count: 0,
1074    });
1075    Ok(Default::default())
1076}
1077
1078fn checks_topics_and_data(checks: [bool; 5], expected: &RawLog, log: &RawLog) -> bool {
1079    if log.topics().len() != expected.topics().len() {
1080        return false;
1081    }
1082
1083    // Check topics.
1084    if !log
1085        .topics()
1086        .iter()
1087        .enumerate()
1088        .filter(|(i, _)| checks[*i])
1089        .all(|(i, topic)| topic == &expected.topics()[i])
1090    {
1091        return false;
1092    }
1093
1094    // Check data
1095    if checks[4] && expected.data.as_ref() != log.data.as_ref() {
1096        return false;
1097    }
1098
1099    true
1100}
1101
1102fn decode_event(
1103    identifier: &foundry_evm_traces::identifier::SignaturesIdentifier,
1104    log: &RawLog,
1105) -> Option<DecodedCallLog> {
1106    let topics = log.topics();
1107    if topics.is_empty() {
1108        return None;
1109    }
1110    let t0 = topics[0]; // event sig
1111    // Try to identify the event
1112    let event = foundry_common::block_on(identifier.identify_event(t0))?;
1113
1114    // Check if event already has indexed information from signatures
1115    let has_indexed_info = event.inputs.iter().any(|p| p.indexed);
1116    // Only use get_indexed_event if the event doesn't have indexing info
1117    let indexed_event = if has_indexed_info { event } else { get_indexed_event(event, log) };
1118
1119    // Try to decode the event
1120    if let Ok(decoded) = indexed_event.decode_log(log) {
1121        let params = reconstruct_params(&indexed_event, &decoded);
1122
1123        let decoded_params = params
1124            .into_iter()
1125            .zip(indexed_event.inputs.iter())
1126            .map(|(param, input)| (input.name.clone(), format_token(&param)))
1127            .collect();
1128
1129        return Some(DecodedCallLog {
1130            name: Some(indexed_event.name),
1131            params: Some(decoded_params),
1132        });
1133    }
1134
1135    None
1136}
1137
1138/// Restore the order of the params of a decoded event
1139fn reconstruct_params(event: &Event, decoded: &alloy_dyn_abi::DecodedEvent) -> Vec<DynSolValue> {
1140    let mut indexed = 0;
1141    let mut unindexed = 0;
1142    let mut inputs = vec![];
1143    for input in &event.inputs {
1144        if input.indexed && indexed < decoded.indexed.len() {
1145            inputs.push(decoded.indexed[indexed].clone());
1146            indexed += 1;
1147        } else if unindexed < decoded.body.len() {
1148            inputs.push(decoded.body[unindexed].clone());
1149            unindexed += 1;
1150        }
1151    }
1152    inputs
1153}
1154
1155/// Gets a detailed mismatch message for emit assertions
1156pub(crate) fn get_emit_mismatch_message(
1157    checks: [bool; 5],
1158    expected: &RawLog,
1159    actual: &RawLog,
1160    is_anonymous: bool,
1161    expected_decoded: Option<&DecodedCallLog>,
1162    actual_decoded: Option<&DecodedCallLog>,
1163) -> String {
1164    // Early return for completely different events or incompatible structures
1165
1166    // 1. Different number of topics
1167    if actual.topics().len() != expected.topics().len() {
1168        return name_mismatched_logs(expected_decoded, actual_decoded);
1169    }
1170
1171    // 2. Different event signatures (for non-anonymous events)
1172    if !is_anonymous
1173        && checks[0]
1174        && (!expected.topics().is_empty() && !actual.topics().is_empty())
1175        && expected.topics()[0] != actual.topics()[0]
1176    {
1177        return name_mismatched_logs(expected_decoded, actual_decoded);
1178    }
1179
1180    let expected_data = expected.data.as_ref();
1181    let actual_data = actual.data.as_ref();
1182
1183    // 3. Check data
1184    if checks[4] && expected_data != actual_data {
1185        // Different lengths or not ABI-encoded
1186        if expected_data.len() != actual_data.len()
1187            || !expected_data.len().is_multiple_of(32)
1188            || expected_data.is_empty()
1189        {
1190            return name_mismatched_logs(expected_decoded, actual_decoded);
1191        }
1192    }
1193
1194    // expected and actual events are the same, so check individual parameters
1195    let mut mismatches = Vec::new();
1196
1197    // Check topics (indexed parameters)
1198    for (i, (expected_topic, actual_topic)) in
1199        expected.topics().iter().zip(actual.topics().iter()).enumerate()
1200    {
1201        // Skip topic[0] for non-anonymous events (already checked above)
1202        if i == 0 && !is_anonymous {
1203            continue;
1204        }
1205
1206        // Only check if the corresponding check flag is set
1207        if i < checks.len() && checks[i] && expected_topic != actual_topic {
1208            let param_idx = if is_anonymous {
1209                i // For anonymous events, topic[0] is param 0
1210            } else {
1211                i - 1 // For regular events, topic[0] is event signature, so topic[1] is param 0
1212            };
1213            mismatches
1214                .push(format!("param {param_idx}: expected={expected_topic}, got={actual_topic}"));
1215        }
1216    }
1217
1218    // Check data (non-indexed parameters)
1219    if checks[4] && expected_data != actual_data {
1220        let num_indexed_params = if is_anonymous {
1221            expected.topics().len()
1222        } else {
1223            expected.topics().len().saturating_sub(1)
1224        };
1225
1226        for (i, (expected_chunk, actual_chunk)) in
1227            expected_data.chunks(32).zip(actual_data.chunks(32)).enumerate()
1228        {
1229            if expected_chunk != actual_chunk {
1230                let param_idx = num_indexed_params + i;
1231                mismatches.push(format!(
1232                    "param {}: expected={}, got={}",
1233                    param_idx,
1234                    hex::encode_prefixed(expected_chunk),
1235                    hex::encode_prefixed(actual_chunk)
1236                ));
1237            }
1238        }
1239    }
1240
1241    if mismatches.is_empty() {
1242        name_mismatched_logs(expected_decoded, actual_decoded)
1243    } else {
1244        // Build the error message with event names if available
1245        let event_prefix = match (expected_decoded, actual_decoded) {
1246            (Some(expected_dec), Some(actual_dec)) if expected_dec.name == actual_dec.name => {
1247                format!(
1248                    "{} param mismatch",
1249                    expected_dec.name.as_ref().unwrap_or(&"log".to_string())
1250                )
1251            }
1252            _ => {
1253                if is_anonymous {
1254                    "anonymous log mismatch".to_string()
1255                } else {
1256                    "log mismatch".to_string()
1257                }
1258            }
1259        };
1260
1261        // Add parameter details if available from decoded events
1262        let detailed_mismatches = if let (Some(expected_dec), Some(actual_dec)) =
1263            (expected_decoded, actual_decoded)
1264            && let (Some(expected_params), Some(actual_params)) =
1265                (&expected_dec.params, &actual_dec.params)
1266        {
1267            mismatches
1268                .into_iter()
1269                .map(|basic_mismatch| {
1270                    // Try to find the parameter name and decoded value
1271                    if let Some(param_idx) = basic_mismatch
1272                        .split(' ')
1273                        .nth(1)
1274                        .and_then(|s| s.trim_end_matches(':').parse::<usize>().ok())
1275                        && param_idx < expected_params.len()
1276                        && param_idx < actual_params.len()
1277                    {
1278                        let (expected_name, expected_value) = &expected_params[param_idx];
1279                        let (_actual_name, actual_value) = &actual_params[param_idx];
1280                        let param_name = if !expected_name.is_empty() {
1281                            expected_name
1282                        } else {
1283                            &format!("param{param_idx}")
1284                        };
1285                        return format!(
1286                            "{param_name}: expected={expected_value}, got={actual_value}",
1287                        );
1288                    }
1289                    basic_mismatch
1290                })
1291                .collect::<Vec<_>>()
1292        } else {
1293            mismatches
1294        };
1295
1296        format!("{} at {}", event_prefix, detailed_mismatches.join(", "))
1297    }
1298}
1299
1300/// Formats the generic mismatch message: "log != expected log" to include event names if available
1301fn name_mismatched_logs(
1302    expected_decoded: Option<&DecodedCallLog>,
1303    actual_decoded: Option<&DecodedCallLog>,
1304) -> String {
1305    let expected_name = expected_decoded.and_then(|d| d.name.as_deref()).unwrap_or("log");
1306    let actual_name = actual_decoded.and_then(|d| d.name.as_deref()).unwrap_or("log");
1307    format!("{actual_name} != expected {expected_name}")
1308}
1309
1310fn expect_safe_memory(state: &mut Cheatcodes, start: u64, end: u64, depth: u64) -> Result {
1311    ensure!(start < end, "memory range start ({start}) is greater than end ({end})");
1312    #[expect(clippy::single_range_in_vec_init)] // Wanted behaviour
1313    let offsets = state.allowed_mem_writes.entry(depth).or_insert_with(|| vec![0..0x60]);
1314    offsets.push(start..end);
1315    Ok(Default::default())
1316}