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<Vec<u8>>,
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_deref()
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    interpreter: &mut Interpreter,
797) {
798    // Fill or check the expected emits.
799    // We expect for emit checks to be filled as they're declared (from oldest to newest),
800    // so we fill them and push them to the back of the queue.
801    // If the user has properly filled all the emits, they'll end up in their original order.
802    // If not, the queue will not be in the order the events will be intended to be filled,
803    // and we'll be able to later detect this and bail.
804
805    // First, we can return early if all events have been matched.
806    // This allows a contract to arbitrarily emit more events than expected (additive behavior),
807    // as long as all the previous events were matched in the order they were expected to be.
808    if state.expected_emits.iter().all(|(expected, _)| expected.found) {
809        return;
810    }
811
812    let should_fill_logs = state.expected_emits.iter().any(|(expected, _)| expected.log.is_none());
813    let index_to_fill_or_check = if should_fill_logs {
814        // If there's anything to fill, we start with the last event to match in the queue
815        // (without taking into account events already matched).
816        state
817            .expected_emits
818            .iter()
819            .position(|(emit, _)| emit.found)
820            .unwrap_or(state.expected_emits.len())
821            .saturating_sub(1)
822    } else {
823        // Otherwise, if all expected logs are filled, we start to check any unmatched event
824        // in the declared order, so we start from the front (like a queue).
825        0
826    };
827
828    let (mut event_to_fill_or_check, mut count_map) = state
829        .expected_emits
830        .remove(index_to_fill_or_check)
831        .expect("we should have an emit to fill or check");
832
833    let Some(expected) = &event_to_fill_or_check.log else {
834        // Unless the caller is trying to match an anonymous event, the first topic must be
835        // filled.
836        if event_to_fill_or_check.anonymous || !log.topics().is_empty() {
837            event_to_fill_or_check.log = Some(log.data.clone());
838            // If we only filled the expected log then we put it back at the same position.
839            state
840                .expected_emits
841                .insert(index_to_fill_or_check, (event_to_fill_or_check, count_map));
842        } else {
843            interpreter.bytecode.set_action(InterpreterAction::new_return(
844                InstructionResult::Revert,
845                Error::encode("use vm.expectEmitAnonymous to match anonymous events"),
846                interpreter.gas,
847            ));
848        }
849        return;
850    };
851
852    // Increment/set `count` for `log.address` and `log.data`
853    match count_map.entry(log.address) {
854        Entry::Occupied(mut entry) => {
855            // Checks and inserts the log into the map.
856            // If the log doesn't pass the checks, it is ignored and `count` is not incremented.
857            let log_count_map = entry.get_mut();
858            log_count_map.insert(&log.data);
859        }
860        Entry::Vacant(entry) => {
861            let mut log_count_map = LogCountMap::new(&event_to_fill_or_check);
862
863            if log_count_map.satisfies_checks(&log.data) {
864                log_count_map.insert(&log.data);
865
866                // Entry is only inserted if it satisfies the checks.
867                entry.insert(log_count_map);
868            }
869        }
870    }
871
872    event_to_fill_or_check.found = || -> bool {
873        if !checks_topics_and_data(event_to_fill_or_check.checks, expected, log) {
874            // Store detailed mismatch information
875
876            // Try to decode the events if we have a signature identifier
877            let (expected_decoded, actual_decoded) = if let Some(signatures_identifier) =
878                &state.signatures_identifier
879                && !event_to_fill_or_check.anonymous
880            {
881                (
882                    decode_event(signatures_identifier, expected),
883                    decode_event(signatures_identifier, log),
884                )
885            } else {
886                (None, None)
887            };
888            event_to_fill_or_check.mismatch_error = Some(get_emit_mismatch_message(
889                event_to_fill_or_check.checks,
890                expected,
891                log,
892                event_to_fill_or_check.anonymous,
893                expected_decoded.as_ref(),
894                actual_decoded.as_ref(),
895            ));
896            return false;
897        }
898
899        // Maybe match source address.
900        if event_to_fill_or_check
901            .address
902            .is_some_and(|addr| addr.to_checksum(None) != log.address.to_checksum(None))
903        {
904            event_to_fill_or_check.mismatch_error = Some(format!(
905                "log emitter mismatch: expected={:#x}, got={:#x}",
906                event_to_fill_or_check.address.unwrap(),
907                log.address
908            ));
909            return false;
910        }
911
912        let expected_count = event_to_fill_or_check.count;
913
914        match event_to_fill_or_check.address {
915            Some(emitter) => count_map
916                .get(&emitter)
917                .is_some_and(|log_map| log_map.count(&log.data) >= expected_count),
918            None => count_map
919                .values()
920                .find(|log_map| log_map.satisfies_checks(&log.data))
921                .is_some_and(|map| map.count(&log.data) >= expected_count),
922        }
923    }();
924
925    // If we found the event, we can push it to the back of the queue
926    // and begin expecting the next event.
927    if event_to_fill_or_check.found {
928        state.expected_emits.push_back((event_to_fill_or_check, count_map));
929    } else {
930        // We did not match this event, so we need to keep waiting for the right one to
931        // appear.
932        state.expected_emits.push_front((event_to_fill_or_check, count_map));
933    }
934}
935
936/// Handles expected emits specified by the `expectEmit` cheatcodes.
937///
938/// The second element of the tuple counts the number of times the log has been emitted by a
939/// particular address
940pub type ExpectedEmitTracker = VecDeque<(ExpectedEmit, AddressHashMap<LogCountMap>)>;
941
942#[derive(Clone, Debug, Default)]
943pub struct LogCountMap {
944    checks: [bool; 5],
945    expected_log: RawLog,
946    map: HashMap<RawLog, u64>,
947}
948
949impl LogCountMap {
950    /// Instantiates `LogCountMap`.
951    fn new(expected_emit: &ExpectedEmit) -> Self {
952        Self {
953            checks: expected_emit.checks,
954            expected_log: expected_emit.log.clone().expect("log should be filled here"),
955            map: Default::default(),
956        }
957    }
958
959    /// Inserts a log into the map and increments the count.
960    ///
961    /// The log must pass all checks against the expected log for the count to increment.
962    ///
963    /// Returns true if the log was inserted and count was incremented.
964    fn insert(&mut self, log: &RawLog) -> bool {
965        // If its already in the map, increment the count without checking.
966        if self.map.contains_key(log) {
967            self.map.entry(log.clone()).and_modify(|c| *c += 1);
968
969            return true;
970        }
971
972        if !self.satisfies_checks(log) {
973            return false;
974        }
975
976        self.map.entry(log.clone()).and_modify(|c| *c += 1).or_insert(1);
977
978        true
979    }
980
981    /// Checks the incoming raw log against the expected logs topics and data.
982    fn satisfies_checks(&self, log: &RawLog) -> bool {
983        checks_topics_and_data(self.checks, &self.expected_log, log)
984    }
985
986    pub fn count(&self, log: &RawLog) -> u64 {
987        if !self.satisfies_checks(log) {
988            return 0;
989        }
990
991        self.count_unchecked()
992    }
993
994    pub fn count_unchecked(&self) -> u64 {
995        self.map.values().sum()
996    }
997}
998
999fn expect_create(
1000    state: &mut Cheatcodes,
1001    bytecode: Bytes,
1002    deployer: Address,
1003    create_scheme: CreateScheme,
1004) -> Result {
1005    let expected_create = ExpectedCreate { bytecode, deployer, create_scheme };
1006    state.expected_creates.push(expected_create);
1007
1008    Ok(Default::default())
1009}
1010
1011fn expect_revert(
1012    state: &mut Cheatcodes,
1013    reason: Option<&[u8]>,
1014    depth: usize,
1015    cheatcode: bool,
1016    partial_match: bool,
1017    reverter: Option<Address>,
1018    count: u64,
1019) -> Result {
1020    ensure!(
1021        state.expected_revert.is_none(),
1022        "you must call another function prior to expecting a second revert"
1023    );
1024    state.expected_revert = Some(ExpectedRevert {
1025        reason: reason.map(<[_]>::to_vec),
1026        depth,
1027        kind: if cheatcode {
1028            ExpectedRevertKind::Cheatcode { pending_processing: true }
1029        } else {
1030            ExpectedRevertKind::Default
1031        },
1032        partial_match,
1033        reverter,
1034        reverted_by: None,
1035        max_depth: depth,
1036        count,
1037        actual_count: 0,
1038    });
1039    Ok(Default::default())
1040}
1041
1042fn checks_topics_and_data(checks: [bool; 5], expected: &RawLog, log: &RawLog) -> bool {
1043    if log.topics().len() != expected.topics().len() {
1044        return false;
1045    }
1046
1047    // Check topics.
1048    if !log
1049        .topics()
1050        .iter()
1051        .enumerate()
1052        .filter(|(i, _)| checks[*i])
1053        .all(|(i, topic)| topic == &expected.topics()[i])
1054    {
1055        return false;
1056    }
1057
1058    // Check data
1059    if checks[4] && expected.data.as_ref() != log.data.as_ref() {
1060        return false;
1061    }
1062
1063    true
1064}
1065
1066fn decode_event(
1067    identifier: &foundry_evm_traces::identifier::SignaturesIdentifier,
1068    log: &RawLog,
1069) -> Option<DecodedCallLog> {
1070    let topics = log.topics();
1071    if topics.is_empty() {
1072        return None;
1073    }
1074    let t0 = topics[0]; // event sig
1075    // Try to identify the event
1076    let event = foundry_common::block_on(identifier.identify_event(t0))?;
1077
1078    // Check if event already has indexed information from signatures
1079    let has_indexed_info = event.inputs.iter().any(|p| p.indexed);
1080    // Only use get_indexed_event if the event doesn't have indexing info
1081    let indexed_event = if has_indexed_info { event } else { get_indexed_event(event, log) };
1082
1083    // Try to decode the event
1084    if let Ok(decoded) = indexed_event.decode_log(log) {
1085        let params = reconstruct_params(&indexed_event, &decoded);
1086
1087        let decoded_params = params
1088            .into_iter()
1089            .zip(indexed_event.inputs.iter())
1090            .map(|(param, input)| (input.name.clone(), format_token(&param)))
1091            .collect();
1092
1093        return Some(DecodedCallLog {
1094            name: Some(indexed_event.name),
1095            params: Some(decoded_params),
1096        });
1097    }
1098
1099    None
1100}
1101
1102/// Restore the order of the params of a decoded event
1103fn reconstruct_params(event: &Event, decoded: &alloy_dyn_abi::DecodedEvent) -> Vec<DynSolValue> {
1104    let mut indexed = 0;
1105    let mut unindexed = 0;
1106    let mut inputs = vec![];
1107    for input in &event.inputs {
1108        if input.indexed && indexed < decoded.indexed.len() {
1109            inputs.push(decoded.indexed[indexed].clone());
1110            indexed += 1;
1111        } else if unindexed < decoded.body.len() {
1112            inputs.push(decoded.body[unindexed].clone());
1113            unindexed += 1;
1114        }
1115    }
1116    inputs
1117}
1118
1119/// Gets a detailed mismatch message for emit assertions
1120pub(crate) fn get_emit_mismatch_message(
1121    checks: [bool; 5],
1122    expected: &RawLog,
1123    actual: &RawLog,
1124    is_anonymous: bool,
1125    expected_decoded: Option<&DecodedCallLog>,
1126    actual_decoded: Option<&DecodedCallLog>,
1127) -> String {
1128    // Early return for completely different events or incompatible structures
1129
1130    // 1. Different number of topics
1131    if actual.topics().len() != expected.topics().len() {
1132        return name_mismatched_logs(expected_decoded, actual_decoded);
1133    }
1134
1135    // 2. Different event signatures (for non-anonymous events)
1136    if !is_anonymous
1137        && checks[0]
1138        && (!expected.topics().is_empty() && !actual.topics().is_empty())
1139        && expected.topics()[0] != actual.topics()[0]
1140    {
1141        return name_mismatched_logs(expected_decoded, actual_decoded);
1142    }
1143
1144    let expected_data = expected.data.as_ref();
1145    let actual_data = actual.data.as_ref();
1146
1147    // 3. Check data
1148    if checks[4] && expected_data != actual_data {
1149        // Different lengths or not ABI-encoded
1150        if expected_data.len() != actual_data.len()
1151            || !expected_data.len().is_multiple_of(32)
1152            || expected_data.is_empty()
1153        {
1154            return name_mismatched_logs(expected_decoded, actual_decoded);
1155        }
1156    }
1157
1158    // expected and actual events are the same, so check individual parameters
1159    let mut mismatches = Vec::new();
1160
1161    // Check topics (indexed parameters)
1162    for (i, (expected_topic, actual_topic)) in
1163        expected.topics().iter().zip(actual.topics().iter()).enumerate()
1164    {
1165        // Skip topic[0] for non-anonymous events (already checked above)
1166        if i == 0 && !is_anonymous {
1167            continue;
1168        }
1169
1170        // Only check if the corresponding check flag is set
1171        if i < checks.len() && checks[i] && expected_topic != actual_topic {
1172            let param_idx = if is_anonymous {
1173                i // For anonymous events, topic[0] is param 0
1174            } else {
1175                i - 1 // For regular events, topic[0] is event signature, so topic[1] is param 0
1176            };
1177            mismatches
1178                .push(format!("param {param_idx}: expected={expected_topic}, got={actual_topic}"));
1179        }
1180    }
1181
1182    // Check data (non-indexed parameters)
1183    if checks[4] && expected_data != actual_data {
1184        let num_indexed_params = if is_anonymous {
1185            expected.topics().len()
1186        } else {
1187            expected.topics().len().saturating_sub(1)
1188        };
1189
1190        for (i, (expected_chunk, actual_chunk)) in
1191            expected_data.chunks(32).zip(actual_data.chunks(32)).enumerate()
1192        {
1193            if expected_chunk != actual_chunk {
1194                let param_idx = num_indexed_params + i;
1195                mismatches.push(format!(
1196                    "param {}: expected={}, got={}",
1197                    param_idx,
1198                    hex::encode_prefixed(expected_chunk),
1199                    hex::encode_prefixed(actual_chunk)
1200                ));
1201            }
1202        }
1203    }
1204
1205    if mismatches.is_empty() {
1206        name_mismatched_logs(expected_decoded, actual_decoded)
1207    } else {
1208        // Build the error message with event names if available
1209        let event_prefix = match (expected_decoded, actual_decoded) {
1210            (Some(expected_dec), Some(actual_dec)) if expected_dec.name == actual_dec.name => {
1211                format!(
1212                    "{} param mismatch",
1213                    expected_dec.name.as_ref().unwrap_or(&"log".to_string())
1214                )
1215            }
1216            _ => {
1217                if is_anonymous {
1218                    "anonymous log mismatch".to_string()
1219                } else {
1220                    "log mismatch".to_string()
1221                }
1222            }
1223        };
1224
1225        // Add parameter details if available from decoded events
1226        let detailed_mismatches = if let (Some(expected_dec), Some(actual_dec)) =
1227            (expected_decoded, actual_decoded)
1228            && let (Some(expected_params), Some(actual_params)) =
1229                (&expected_dec.params, &actual_dec.params)
1230        {
1231            mismatches
1232                .into_iter()
1233                .map(|basic_mismatch| {
1234                    // Try to find the parameter name and decoded value
1235                    if let Some(param_idx) = basic_mismatch
1236                        .split(' ')
1237                        .nth(1)
1238                        .and_then(|s| s.trim_end_matches(':').parse::<usize>().ok())
1239                        && param_idx < expected_params.len()
1240                        && param_idx < actual_params.len()
1241                    {
1242                        let (expected_name, expected_value) = &expected_params[param_idx];
1243                        let (_actual_name, actual_value) = &actual_params[param_idx];
1244                        let param_name = if !expected_name.is_empty() {
1245                            expected_name
1246                        } else {
1247                            &format!("param{param_idx}")
1248                        };
1249                        return format!(
1250                            "{param_name}: expected={expected_value}, got={actual_value}",
1251                        );
1252                    }
1253                    basic_mismatch
1254                })
1255                .collect::<Vec<_>>()
1256        } else {
1257            mismatches
1258        };
1259
1260        format!("{} at {}", event_prefix, detailed_mismatches.join(", "))
1261    }
1262}
1263
1264/// Formats the generic mismatch message: "log != expected log" to include event names if available
1265fn name_mismatched_logs(
1266    expected_decoded: Option<&DecodedCallLog>,
1267    actual_decoded: Option<&DecodedCallLog>,
1268) -> String {
1269    let expected_name = expected_decoded.and_then(|d| d.name.as_deref()).unwrap_or("log");
1270    let actual_name = actual_decoded.and_then(|d| d.name.as_deref()).unwrap_or("log");
1271    format!("{actual_name} != expected {expected_name}")
1272}
1273
1274fn expect_safe_memory(state: &mut Cheatcodes, start: u64, end: u64, depth: u64) -> Result {
1275    ensure!(start < end, "memory range start ({start}) is greater than end ({end})");
1276    #[expect(clippy::single_range_in_vec_init)] // Wanted behaviour
1277    let offsets = state.allowed_mem_writes.entry(depth).or_insert_with(|| vec![0..0x60]);
1278    offsets.push(start..end);
1279    Ok(Default::default())
1280}