Skip to main content

foundry_cheatcodes/test/
expect.rs

1use std::fmt::{self, Display};
2
3use crate::{
4    Cheatcode, Cheatcodes, CheatcodesCore, CheatsCtxt, Error, Result,
5    Vm::*,
6    expected_emit::{ExpectedEmit, observe_log},
7};
8use alloy_primitives::{
9    Address, Bytes, Log, LogData as RawLog, U256, hex, keccak256,
10    map::{HashMap, hash_map::Entry},
11};
12use alloy_sol_types::{SolCall, SolValue};
13use foundry_evm_core::evm::FoundryEvmNetwork;
14use itertools::Itertools;
15use revm::interpreter::{
16    CallScheme, InstructionResult, Interpreter, InterpreterAction, interpreter_types::LoopControl,
17};
18use tempo_contracts::precompiles::ISignatureVerifier;
19use tempo_precompiles::SIGNATURE_VERIFIER_ADDRESS;
20
21use super::revert_handlers::RevertParameters;
22/// Tracks the expected calls per address.
23///
24/// For each address, we track the expected calls per call data and optional call scheme. We track
25/// it in such manner so that we don't mix together calldatas that only contain selectors and
26/// calldatas that contain selector and arguments (partial and full matches), or unrestricted calls
27/// and calls restricted to a specific scheme.
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, ExpectedCallsForTarget>;
33
34/// Tracks calldata, scheme and count expectations for one target.
35pub type ExpectedCallsForTarget =
36    HashMap<(Bytes, Option<ExpectedCallScheme>), (ExpectedCallData, u64)>;
37
38#[derive(Clone, Debug)]
39pub struct ExpectedCallData {
40    /// The expected value sent in the call
41    pub value: Option<U256>,
42    /// The expected gas supplied to the call
43    pub gas: Option<u64>,
44    /// The expected *minimum* gas supplied to the call
45    pub min_gas: Option<u64>,
46    /// The number of times the call is expected to be made.
47    /// If the type of call is `NonCount`, this is the lower bound for the number of calls
48    /// that must be seen.
49    /// If the type of call is `Count`, this is the exact number of calls that must be seen.
50    pub count: u64,
51    /// The type of expected call.
52    pub call_type: ExpectedCallType,
53}
54
55impl Default for ExpectedCallData {
56    fn default() -> Self {
57        Self {
58            value: None,
59            gas: None,
60            min_gas: None,
61            count: 1,
62            call_type: ExpectedCallType::NonCount,
63        }
64    }
65}
66
67/// The type of expected call.
68#[derive(Clone, Debug, PartialEq, Eq)]
69pub enum ExpectedCallType {
70    /// The call is expected to be made at least once.
71    NonCount,
72    /// The exact number of calls expected.
73    Count,
74}
75
76/// Call kinds used by Foundry expectations independently of the execution engine.
77#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
78pub enum ExpectedCallScheme {
79    /// CALL.
80    Call,
81    /// CALLCODE.
82    CallCode,
83    /// DELEGATECALL.
84    DelegateCall,
85    /// STATICCALL.
86    StaticCall,
87}
88
89impl From<CallScheme> for ExpectedCallScheme {
90    fn from(scheme: CallScheme) -> Self {
91        match scheme {
92            CallScheme::Call => Self::Call,
93            CallScheme::CallCode => Self::CallCode,
94            CallScheme::DelegateCall => Self::DelegateCall,
95            CallScheme::StaticCall => Self::StaticCall,
96        }
97    }
98}
99
100/// The type of expected revert.
101#[derive(Clone, Debug)]
102pub enum ExpectedRevertKind {
103    /// Expects revert from the next non-cheatcode call.
104    Default,
105    /// Expects revert from the next cheatcode call.
106    ///
107    /// The `pending_processing` flag is used to track whether we have exited
108    /// `expectCheatcodeRevert` context or not.
109    /// We have to track it to avoid expecting `expectCheatcodeRevert` call to revert itself.
110    Cheatcode { pending_processing: bool },
111}
112
113#[derive(Clone, Debug)]
114pub struct ExpectedRevert {
115    /// The expected data returned by the revert, None being any.
116    pub reason: Option<Bytes>,
117    /// The depth at which the revert is expected.
118    pub depth: usize,
119    /// The type of expected revert.
120    pub kind: ExpectedRevertKind,
121    /// If true then only the first 4 bytes of expected data returned by the revert are checked.
122    pub partial_match: bool,
123    /// Contract expected to revert next call.
124    pub reverter: Option<Address>,
125    /// Address that reverted the call.
126    pub reverted_by: Option<Address>,
127    /// Max call depth reached during next call execution.
128    pub max_depth: usize,
129    /// Number of times this revert is expected.
130    pub count: u64,
131    /// Actual number of times this revert has been seen.
132    pub actual_count: u64,
133}
134
135#[derive(Clone, Debug)]
136pub struct ExpectedCreate {
137    /// The address that deployed the contract
138    pub deployer: Address,
139    /// Runtime bytecode of the contract
140    pub bytecode: Bytes,
141    /// Whether deployed with CREATE or CREATE2
142    pub create_scheme: CreateScheme,
143}
144
145#[derive(Clone, Debug)]
146pub enum CreateScheme {
147    Create,
148    Create2,
149}
150
151impl Display for CreateScheme {
152    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
153        match self {
154            Self::Create => write!(f, "CREATE"),
155            Self::Create2 => write!(f, "CREATE2"),
156        }
157    }
158}
159
160impl From<revm::context_interface::CreateScheme> for CreateScheme {
161    fn from(scheme: revm::context_interface::CreateScheme) -> Self {
162        match scheme {
163            revm::context_interface::CreateScheme::Create => Self::Create,
164            revm::context_interface::CreateScheme::Create2 { .. } => Self::Create2,
165            _ => unimplemented!("Unsupported create scheme"),
166        }
167    }
168}
169
170impl CreateScheme {
171    pub const fn eq(&self, create_scheme: Self) -> bool {
172        matches!(
173            (self, create_scheme),
174            (Self::Create, Self::Create) | (Self::Create2, Self::Create2 { .. })
175        )
176    }
177}
178
179impl Cheatcode for expectCall_0Call {
180    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
181        let Self { callee, data } = self;
182        expect_call(state, callee, data, None, ExpectedCallData::default())
183    }
184}
185
186impl Cheatcode for expectCall_1Call {
187    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
188        let Self { callee, data, count } = self;
189        expect_call(
190            state,
191            callee,
192            data,
193            None,
194            ExpectedCallData {
195                count: *count,
196                call_type: ExpectedCallType::Count,
197                ..Default::default()
198            },
199        )
200    }
201}
202
203impl Cheatcode for expectCall_2Call {
204    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
205        let Self { callee, msgValue, data } = self;
206        expect_call(
207            state,
208            callee,
209            data,
210            None,
211            ExpectedCallData { value: Some(*msgValue), ..Default::default() },
212        )
213    }
214}
215
216impl Cheatcode for expectCall_3Call {
217    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
218        let Self { callee, msgValue, data, count } = self;
219        expect_call(
220            state,
221            callee,
222            data,
223            None,
224            ExpectedCallData {
225                value: Some(*msgValue),
226                count: *count,
227                call_type: ExpectedCallType::Count,
228                ..Default::default()
229            },
230        )
231    }
232}
233
234impl Cheatcode for expectCall_4Call {
235    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
236        let Self { callee, msgValue, gas, data } = self;
237        expect_call(
238            state,
239            callee,
240            data,
241            None,
242            ExpectedCallData { value: Some(*msgValue), gas: Some(*gas), ..Default::default() },
243        )
244    }
245}
246
247impl Cheatcode for expectCall_5Call {
248    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
249        let Self { callee, msgValue, gas, data, count } = self;
250        expect_call(
251            state,
252            callee,
253            data,
254            None,
255            ExpectedCallData {
256                value: Some(*msgValue),
257                gas: Some(*gas),
258                count: *count,
259                call_type: ExpectedCallType::Count,
260                ..Default::default()
261            },
262        )
263    }
264}
265
266impl Cheatcode for expectDelegateCallCall {
267    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
268        let Self { callee, data } = self;
269        expect_call(
270            state,
271            callee,
272            data,
273            Some(ExpectedCallScheme::DelegateCall),
274            ExpectedCallData::default(),
275        )
276    }
277}
278
279impl Cheatcode for expectCallMinGas_0Call {
280    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
281        let Self { callee, msgValue, minGas, data } = self;
282        expect_call(
283            state,
284            callee,
285            data,
286            None,
287            ExpectedCallData {
288                value: Some(*msgValue),
289                min_gas: Some(*minGas),
290                ..Default::default()
291            },
292        )
293    }
294}
295
296impl Cheatcode for expectCallMinGas_1Call {
297    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
298        let Self { callee, msgValue, minGas, data, count } = self;
299        expect_call(
300            state,
301            callee,
302            data,
303            None,
304            ExpectedCallData {
305                value: Some(*msgValue),
306                min_gas: Some(*minGas),
307                count: *count,
308                call_type: ExpectedCallType::Count,
309                ..Default::default()
310            },
311        )
312    }
313}
314
315impl Cheatcode for expectEmit_0Call {
316    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
317        let Self { checkTopic1, checkTopic2, checkTopic3, checkData } = *self;
318        expect_emit(
319            ccx.state,
320            ccx.depth(),
321            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
322            None,
323            false,
324            1,
325        )
326    }
327}
328
329impl Cheatcode for expectEmit_1Call {
330    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
331        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;
332        expect_emit(
333            ccx.state,
334            ccx.depth(),
335            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
336            Some(emitter),
337            false,
338            1,
339        )
340    }
341}
342
343impl Cheatcode for expectEmit_2Call {
344    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
345        let Self {} = self;
346        expect_emit(ccx.state, ccx.depth(), [true; 5], None, false, 1)
347    }
348}
349
350impl Cheatcode for expectEmit_3Call {
351    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
352        let Self { emitter } = *self;
353        expect_emit(ccx.state, ccx.depth(), [true; 5], Some(emitter), false, 1)
354    }
355}
356
357impl Cheatcode for expectEmit_4Call {
358    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
359        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, count } = *self;
360        expect_emit(
361            ccx.state,
362            ccx.depth(),
363            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
364            None,
365            false,
366            count,
367        )
368    }
369}
370
371impl Cheatcode for expectEmit_5Call {
372    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
373        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter, count } = *self;
374        expect_emit(
375            ccx.state,
376            ccx.depth(),
377            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
378            Some(emitter),
379            false,
380            count,
381        )
382    }
383}
384
385impl Cheatcode for expectEmit_6Call {
386    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
387        let Self { count } = *self;
388        expect_emit(ccx.state, ccx.depth(), [true; 5], None, false, count)
389    }
390}
391
392impl Cheatcode for expectEmit_7Call {
393    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
394        let Self { emitter, count } = *self;
395        expect_emit(ccx.state, ccx.depth(), [true; 5], Some(emitter), false, count)
396    }
397}
398
399impl Cheatcode for expectEmitAnonymous_0Call {
400    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
401        let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData } = *self;
402        expect_emit(
403            ccx.state,
404            ccx.depth(),
405            [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],
406            None,
407            true,
408            1,
409        )
410    }
411}
412
413impl Cheatcode for expectEmitAnonymous_1Call {
414    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
415        let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;
416        expect_emit(
417            ccx.state,
418            ccx.depth(),
419            [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],
420            Some(emitter),
421            true,
422            1,
423        )
424    }
425}
426
427impl Cheatcode for expectEmitAnonymous_2Call {
428    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
429        let Self {} = self;
430        expect_emit(ccx.state, ccx.depth(), [true; 5], None, true, 1)
431    }
432}
433
434impl Cheatcode for expectEmitAnonymous_3Call {
435    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
436        let Self { emitter } = *self;
437        expect_emit(ccx.state, ccx.depth(), [true; 5], Some(emitter), true, 1)
438    }
439}
440
441impl Cheatcode for expectCreateCall {
442    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
443        let Self { bytecode, deployer } = self;
444        expect_create(ccx.state, bytecode.clone(), *deployer, CreateScheme::Create)
445    }
446}
447
448impl Cheatcode for expectCreate2Call {
449    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
450        let Self { bytecode, deployer } = self;
451        expect_create(ccx.state, bytecode.clone(), *deployer, CreateScheme::Create2)
452    }
453}
454
455impl Cheatcode for expectTip20LogoURIUpdatedCall {
456    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
457        let Self { token, updater, newLogoURI } = self;
458        expect_logo_uri_updated(ccx, token, updater, newLogoURI)
459    }
460}
461
462impl Cheatcode for expectKeychainVerifiedCall {
463    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
464        let Self { account, digest, signature } = self;
465        expect_keychain_verified(state, *account, *digest, signature.clone(), false)
466    }
467}
468
469impl Cheatcode for expectKeychainAdminVerifiedCall {
470    fn apply_context(&self, state: &mut CheatcodesCore) -> Result {
471        let Self { account, digest, signature } = self;
472        expect_keychain_verified(state, *account, *digest, signature.clone(), true)
473    }
474}
475
476impl Cheatcode for expectLogoURIUpdatedCall {
477    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
478        let Self { token, updater, newLogoURI } = self;
479        expect_logo_uri_updated(ccx, token, updater, newLogoURI)
480    }
481}
482
483fn expect_keychain_verified(
484    state: &mut CheatcodesCore,
485    account: Address,
486    digest: alloy_primitives::B256,
487    signature: Bytes,
488    admin: bool,
489) -> Result {
490    let calldata = if admin {
491        ISignatureVerifier::verifyKeychainAdminCall { account, hash: digest, signature }
492            .abi_encode()
493    } else {
494        ISignatureVerifier::verifyKeychainCall { account, hash: digest, signature }.abi_encode()
495    };
496    expect_call(
497        state,
498        &SIGNATURE_VERIFIER_ADDRESS,
499        &Bytes::from(calldata),
500        None,
501        ExpectedCallData::default(),
502    )
503}
504
505fn expect_logo_uri_updated<FEN: FoundryEvmNetwork>(
506    ccx: &mut CheatsCtxt<'_, '_, FEN>,
507    token: &Address,
508    updater: &Address,
509    new_logo_uri: &str,
510) -> Result {
511    let expected_emit = ExpectedEmit {
512        depth: ccx.depth(),
513        log: Some(RawLog::new_unchecked(
514            vec![keccak256("LogoURIUpdated(address,string)"), updater.into_word()],
515            new_logo_uri.abi_encode().into(),
516        )),
517        checks: [true, true, false, false, true],
518        address: Some(*token),
519        anonymous: false,
520        found: false,
521        count: 1,
522        mismatch_error: None,
523    };
524    ccx.state.expected_emits.push_back((expected_emit, Default::default()));
525    Ok(Default::default())
526}
527
528impl Cheatcode for expectRevert_0Call {
529    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
530        let Self {} = self;
531        expect_revert(ccx.state, None, ccx.depth(), false, false, None, 1)
532    }
533}
534
535impl Cheatcode for expectRevert_1Call {
536    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
537        let Self { revertData } = self;
538        expect_revert(ccx.state, Some(revertData.as_ref()), ccx.depth(), false, false, None, 1)
539    }
540}
541
542impl Cheatcode for expectRevert_2Call {
543    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
544        let Self { revertData } = self;
545        expect_revert(ccx.state, Some(revertData), ccx.depth(), false, false, None, 1)
546    }
547}
548
549impl Cheatcode for expectRevert_3Call {
550    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
551        let Self { reverter } = self;
552        expect_revert(ccx.state, None, ccx.depth(), false, false, Some(*reverter), 1)
553    }
554}
555
556impl Cheatcode for expectRevert_4Call {
557    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
558        let Self { revertData, reverter } = self;
559        expect_revert(
560            ccx.state,
561            Some(revertData.as_ref()),
562            ccx.depth(),
563            false,
564            false,
565            Some(*reverter),
566            1,
567        )
568    }
569}
570
571impl Cheatcode for expectRevert_5Call {
572    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
573        let Self { revertData, reverter } = self;
574        expect_revert(ccx.state, Some(revertData), ccx.depth(), false, false, Some(*reverter), 1)
575    }
576}
577
578impl Cheatcode for expectRevert_6Call {
579    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
580        let Self { count } = self;
581        expect_revert(ccx.state, None, ccx.depth(), false, false, None, *count)
582    }
583}
584
585impl Cheatcode for expectRevert_7Call {
586    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
587        let Self { revertData, count } = self;
588        expect_revert(ccx.state, Some(revertData.as_ref()), ccx.depth(), false, false, None, *count)
589    }
590}
591
592impl Cheatcode for expectRevert_8Call {
593    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
594        let Self { revertData, count } = self;
595        expect_revert(ccx.state, Some(revertData), ccx.depth(), false, false, None, *count)
596    }
597}
598
599impl Cheatcode for expectRevert_9Call {
600    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
601        let Self { reverter, count } = self;
602        expect_revert(ccx.state, None, ccx.depth(), false, false, Some(*reverter), *count)
603    }
604}
605
606impl Cheatcode for expectRevert_10Call {
607    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
608        let Self { revertData, reverter, count } = self;
609        expect_revert(
610            ccx.state,
611            Some(revertData.as_ref()),
612            ccx.depth(),
613            false,
614            false,
615            Some(*reverter),
616            *count,
617        )
618    }
619}
620
621impl Cheatcode for expectRevert_11Call {
622    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
623        let Self { revertData, reverter, count } = self;
624        expect_revert(
625            ccx.state,
626            Some(revertData),
627            ccx.depth(),
628            false,
629            false,
630            Some(*reverter),
631            *count,
632        )
633    }
634}
635
636impl Cheatcode for expectPartialRevert_0Call {
637    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
638        let Self { revertData } = self;
639        expect_revert(ccx.state, Some(revertData.as_ref()), ccx.depth(), false, true, None, 1)
640    }
641}
642
643impl Cheatcode for expectPartialRevert_1Call {
644    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
645        let Self { revertData, reverter } = self;
646        expect_revert(
647            ccx.state,
648            Some(revertData.as_ref()),
649            ccx.depth(),
650            false,
651            true,
652            Some(*reverter),
653            1,
654        )
655    }
656}
657
658impl Cheatcode for _expectCheatcodeRevert_0Call {
659    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
660        expect_revert(ccx.state, None, ccx.depth(), true, false, None, 1)
661    }
662}
663
664impl Cheatcode for _expectCheatcodeRevert_1Call {
665    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
666        let Self { revertData } = self;
667        expect_revert(ccx.state, Some(revertData.as_ref()), ccx.depth(), true, false, None, 1)
668    }
669}
670
671impl Cheatcode for _expectCheatcodeRevert_2Call {
672    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
673        let Self { revertData } = self;
674        expect_revert(ccx.state, Some(revertData), ccx.depth(), true, false, None, 1)
675    }
676}
677
678impl Cheatcode for expectSafeMemoryCall {
679    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
680        let Self { min, max } = *self;
681        expect_safe_memory(ccx.state, min, max, ccx.depth().try_into()?)
682    }
683}
684
685impl Cheatcode for stopExpectSafeMemoryCall {
686    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
687        let Self {} = self;
688        ccx.state.allowed_mem_writes.remove(&ccx.depth().try_into()?);
689        Ok(Default::default())
690    }
691}
692
693impl Cheatcode for expectSafeMemoryCallCall {
694    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
695        let Self { min, max } = *self;
696        expect_safe_memory(ccx.state, min, max, (ccx.depth() + 1).try_into()?)
697    }
698}
699
700impl RevertParameters for ExpectedRevert {
701    fn reverter(&self) -> Option<Address> {
702        self.reverter
703    }
704
705    fn reason(&self) -> Option<&[u8]> {
706        self.reason.as_ref().map(|b| &***b)
707    }
708
709    fn partial_match(&self) -> bool {
710        self.partial_match
711    }
712}
713
714impl ExpectedRevert {
715    /// Returns whether a call ending at `depth`, at or above the expectation's depth, consumes
716    /// this expectation.
717    ///
718    /// With `internal_expect_revert` enabled, a same-depth revert can satisfy it, but it must not
719    /// be consumed by external calls that succeed (e.g. calls to non-contract addresses that
720    /// return `Stop` before Solidity's own revert).
721    pub(crate) const fn needs_processing(
722        &self,
723        cheatcode_call: bool,
724        call_failed: bool,
725        depth: usize,
726        internal_expect_revert: bool,
727    ) -> bool {
728        let went_deeper = self.max_depth > self.depth;
729        match self.kind {
730            ExpectedRevertKind::Default => {
731                // Cheatcode reverts propagate up; let the outer frame catch them.
732                if cheatcode_call {
733                    return false;
734                }
735                // Any failure satisfies the expectation.
736                if call_failed {
737                    return true;
738                }
739                // Traditional expectRevert: succeeded external call went deeper.
740                if !internal_expect_revert && went_deeper {
741                    return true;
742                }
743                // Test function returned: catch dangling expectations.
744                if depth == 0 {
745                    return true;
746                }
747                // Same-depth success with internal mode off is an error; with it on,
748                // keep waiting for the actual revert.
749                !internal_expect_revert
750            }
751            // `pending_processing == true` means we're in the `call_end` hook for
752            // `vm.expectCheatcodeRevert` and shouldn't expect a revert here.
753            ExpectedRevertKind::Cheatcode { pending_processing } => {
754                cheatcode_call && !pending_processing
755            }
756        }
757    }
758}
759
760/// Registers an expectation keyed by target, calldata and call scheme.
761/// Counted expectations require an exact count and cannot be registered twice or mixed with
762/// non-counted expectations. Repeated non-counted expectations increase the minimum call count.
763fn expect_call(
764    state: &mut CheatcodesCore,
765    target: &Address,
766    calldata: &Bytes,
767    scheme: Option<ExpectedCallScheme>,
768    mut expected: ExpectedCallData,
769) -> Result {
770    let expecteds = state.expected_calls.entry(*target).or_default();
771
772    if let Some(value) = expected.value
773        && value > U256::ZERO
774    {
775        // If the value of the transaction is non-zero, the EVM adds a call stipend of 2300 gas
776        // to ensure that the basic fallback function can be called.
777        let positive_value_cost_stipend = 2300;
778        if let Some(gas) = &mut expected.gas {
779            *gas += positive_value_cost_stipend;
780        }
781        if let Some(min_gas) = &mut expected.min_gas {
782            *min_gas += positive_value_cost_stipend;
783        }
784    }
785
786    match expecteds.entry((calldata.clone(), scheme)) {
787        Entry::Occupied(mut entry) => {
788            ensure!(
789                expected.call_type == ExpectedCallType::NonCount,
790                "counted expected calls can only bet set once"
791            );
792            let (existing, _) = entry.get_mut();
793            ensure!(
794                existing.call_type == ExpectedCallType::NonCount,
795                "cannot overwrite a counted expectCall with a non-counted expectCall"
796            );
797            existing.count += 1;
798        }
799        Entry::Vacant(entry) => {
800            entry.insert((expected, 0));
801        }
802    }
803
804    Ok(Default::default())
805}
806
807/// Counts a call against every matching expectation registered for one target.
808pub(crate) fn observe_call(
809    expected_calls_for_target: &mut ExpectedCallsForTarget,
810    input: &[u8],
811    value: Option<U256>,
812    gas_limit: u64,
813    scheme: ExpectedCallScheme,
814) {
815    // Match every partial/full calldata.
816    for ((calldata, expected_scheme), (expected, actual_count)) in expected_calls_for_target {
817        // Increment actual times seen if all of the following hold.
818        // The calldata is at most as big as this call's input.
819        if calldata.len() <= input.len() &&
820            // Both calldata match, taking the length of the assumed smaller one (which will have at least the selector).
821            input.get(..calldata.len()) == Some(calldata.as_ref()) &&
822            // The value matches, if provided.
823            expected.value.is_none_or(|expected_value| Some(expected_value) == value) &&
824            // The gas matches, if provided.
825            expected.gas.is_none_or(|gas| gas == gas_limit) &&
826            // The minimum gas matches, if provided.
827            expected.min_gas.is_none_or(|min_gas| min_gas <= gas_limit) &&
828            // The call scheme matches, if provided.
829            expected_scheme.is_none_or(|expected_scheme| expected_scheme == scheme)
830        {
831            *actual_count += 1;
832        }
833    }
834}
835
836/// Returns the failure message for the smallest unmet call expectation, if any.
837///
838/// Expectations are ordered by address, calldata and call scheme.
839/// `succeeded` is false for both reverts and halts.
840pub(crate) fn first_unmet_call(tracker: &ExpectedCallTracker, succeeded: bool) -> Option<String> {
841    let (address, calldata, scheme, expected, actual_count) = tracker
842        .iter()
843        .flat_map(|(address, calldatas)| {
844            calldatas.iter().map(move |((calldata, scheme), (expected, actual_count))| {
845                (address, calldata, scheme, expected, actual_count)
846            })
847        })
848        .filter(|(_, _, _, expected, actual_count)| match expected.call_type {
849            // Counted expectations require exactly the requested number of calls.
850            ExpectedCallType::Count => expected.count != **actual_count,
851            // Non-counted expectations require at least the requested number of calls.
852            ExpectedCallType::NonCount => expected.count > **actual_count,
853        })
854        .min_by_key(|(address, calldata, scheme, ..)| {
855            (*address, *calldata, call_scheme_rank(**scheme))
856        })?;
857
858    let ExpectedCallData { gas, min_gas, value, count, .. } = expected;
859    let expected_values = [
860        Some(format!("data {}", hex::encode_prefixed(calldata))),
861        value.as_ref().map(|v| format!("value {v}")),
862        gas.map(|g| format!("gas {g}")),
863        min_gas.map(|g| format!("minimum gas {g}")),
864        scheme.map(|scheme| format!("call type {scheme:?}")),
865    ]
866    .into_iter()
867    .flatten()
868    .join(", ");
869    let but = if succeeded {
870        let s = if *actual_count == 1 { "" } else { "s" };
871        format!("was called {actual_count} time{s}")
872    } else {
873        "the call reverted instead; \
874         ensure you're testing the happy path when using `expectCall`"
875            .to_string()
876    };
877    let s = if *count == 1 { "" } else { "s" };
878    Some(format!(
879        "expected call to {address} with {expected_values} \
880         to be called {count} time{s}, but {but}"
881    ))
882}
883
884const fn call_scheme_rank(scheme: Option<ExpectedCallScheme>) -> u8 {
885    match scheme {
886        None => 0,
887        Some(ExpectedCallScheme::Call) => 1,
888        Some(ExpectedCallScheme::CallCode) => 2,
889        Some(ExpectedCallScheme::DelegateCall) => 3,
890        Some(ExpectedCallScheme::StaticCall) => 4,
891    }
892}
893
894fn expect_emit<FEN: FoundryEvmNetwork>(
895    state: &mut Cheatcodes<FEN>,
896    depth: usize,
897    checks: [bool; 5],
898    address: Option<Address>,
899    anonymous: bool,
900    count: u64,
901) -> Result {
902    let expected_emit = ExpectedEmit {
903        depth,
904        checks,
905        address,
906        found: false,
907        log: None,
908        anonymous,
909        count,
910        mismatch_error: None,
911    };
912    if let Some(found_emit_pos) = state.expected_emits.iter().position(|(emit, _)| emit.found) {
913        // The order of emits already found (back of queue) should not be modified, hence push any
914        // new emit before first found emit.
915        state.expected_emits.insert(found_emit_pos, (expected_emit, Default::default()));
916    } else {
917        // If no expected emits then push new one at the back of queue.
918        state.expected_emits.push_back((expected_emit, Default::default()));
919    }
920
921    Ok(Default::default())
922}
923
924/// Applies an `expectEmit` failure for `log` by reverting the current call, when an interpreter
925/// is available.
926///
927/// Without an interpreter, the failure reason is returned to the caller instead.
928pub(crate) fn handle_expect_emit<FEN: FoundryEvmNetwork>(
929    state: &mut Cheatcodes<FEN>,
930    log: &Log,
931    interpreter: Option<&mut Interpreter>,
932) -> Option<&'static str> {
933    let reason = observe_log(&mut state.expected_emits, log)?;
934    let Some(interpreter) = interpreter else { return Some(reason) };
935    interpreter.bytecode.set_action(InterpreterAction::new_return(
936        InstructionResult::Revert,
937        Error::encode(reason),
938        interpreter.gas,
939    ));
940    None
941}
942
943fn expect_create<FEN: FoundryEvmNetwork>(
944    state: &mut Cheatcodes<FEN>,
945    bytecode: Bytes,
946    deployer: Address,
947    create_scheme: CreateScheme,
948) -> Result {
949    let expected_create = ExpectedCreate { bytecode, deployer, create_scheme };
950    state.expected_creates.push(expected_create);
951
952    Ok(Default::default())
953}
954
955fn expect_revert<FEN: FoundryEvmNetwork>(
956    state: &mut Cheatcodes<FEN>,
957    reason: Option<&[u8]>,
958    depth: usize,
959    cheatcode: bool,
960    partial_match: bool,
961    reverter: Option<Address>,
962    count: u64,
963) -> Result {
964    ensure!(
965        state.expected_revert.is_none(),
966        "you must call another function prior to expecting a second revert"
967    );
968    state.expected_revert = Some(ExpectedRevert {
969        reason: reason.map(Bytes::copy_from_slice),
970        depth,
971        kind: if cheatcode {
972            ExpectedRevertKind::Cheatcode { pending_processing: true }
973        } else {
974            ExpectedRevertKind::Default
975        },
976        partial_match,
977        reverter,
978        reverted_by: None,
979        max_depth: depth,
980        count,
981        actual_count: 0,
982    });
983    Ok(Default::default())
984}
985
986fn expect_safe_memory<FEN: FoundryEvmNetwork>(
987    state: &mut Cheatcodes<FEN>,
988    start: u64,
989    end: u64,
990    depth: u64,
991) -> Result {
992    ensure!(start < end, "memory range start ({start}) is greater than end ({end})");
993    #[expect(clippy::single_range_in_vec_init)] // Wanted behaviour
994    let offsets = state.allowed_mem_writes.entry(depth).or_insert_with(|| vec![0..0x60]);
995    offsets.push(start..end);
996    Ok(Default::default())
997}
998
999/// Removes the first create expectation matched by a completed create.
1000///
1001/// `create_scheme` is only called for expectations with a matching deployer.
1002pub(crate) fn observe_create(
1003    expected_creates: &mut Vec<ExpectedCreate>,
1004    deployer: Address,
1005    create_scheme: impl Fn() -> CreateScheme,
1006    bytecode: &Bytes,
1007) {
1008    if let Some((index, _)) = expected_creates.iter().find_position(|expected_create| {
1009        expected_create.deployer == deployer
1010            && expected_create.create_scheme.eq(create_scheme())
1011            && expected_create.bytecode == *bytecode
1012    }) {
1013        expected_creates.swap_remove(index);
1014    }
1015}
1016
1017/// Returns the failure message for the first unmet create expectation, if any.
1018pub(crate) fn first_unmet_create(expected_creates: &[ExpectedCreate]) -> Option<String> {
1019    let expected_create = expected_creates.first()?;
1020    Some(format!(
1021        "expected {} call by address {} for bytecode {} but not found",
1022        expected_create.create_scheme,
1023        hex::encode_prefixed(expected_create.deployer),
1024        hex::encode_prefixed(&expected_create.bytecode),
1025    ))
1026}
1027
1028#[cfg(test)]
1029mod tests {
1030    use super::*;
1031    use alloy_primitives::{address, bytes};
1032
1033    const TARGET: Address = address!("0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f");
1034
1035    fn expected(
1036        value: Option<U256>,
1037        gas: Option<u64>,
1038        min_gas: Option<u64>,
1039        count: u64,
1040        call_type: ExpectedCallType,
1041    ) -> ExpectedCallData {
1042        ExpectedCallData { value, gas, min_gas, count, call_type }
1043    }
1044
1045    fn tracker(
1046        calldata: Bytes,
1047        scheme: Option<ExpectedCallScheme>,
1048        data: ExpectedCallData,
1049    ) -> ExpectedCallTracker {
1050        let mut tracker = ExpectedCallTracker::default();
1051        tracker.entry(TARGET).or_default().insert((calldata, scheme), (data, 0));
1052        tracker
1053    }
1054
1055    fn seen(
1056        tracker: &ExpectedCallTracker,
1057        calldata: &Bytes,
1058        scheme: Option<ExpectedCallScheme>,
1059    ) -> u64 {
1060        tracker[&TARGET][&(calldata.clone(), scheme)].1
1061    }
1062
1063    fn observe(tracker: &mut ExpectedCallTracker, input: &[u8], value: Option<U256>, gas: u64) {
1064        observe_call(
1065            tracker.get_mut(&TARGET).unwrap(),
1066            input,
1067            value,
1068            gas,
1069            ExpectedCallScheme::Call,
1070        );
1071    }
1072
1073    #[test]
1074    fn observe_call_matches_calldata_prefix() {
1075        let selector = bytes!("771602f7");
1076        let full = bytes!("771602f7aabb");
1077        let mut t = tracker(
1078            selector.clone(),
1079            None,
1080            expected(None, None, None, 1, ExpectedCallType::NonCount),
1081        );
1082        t.entry(TARGET).or_default().insert(
1083            (full.clone(), None),
1084            (expected(None, None, None, 1, ExpectedCallType::NonCount), 0),
1085        );
1086
1087        observe(&mut t, &full, None, 0);
1088        observe(&mut t, &selector, None, 0);
1089        observe(&mut t, &bytes!("12345678"), None, 0);
1090
1091        assert_eq!(seen(&t, &selector, None), 2);
1092        assert_eq!(seen(&t, &full, None), 1);
1093    }
1094
1095    #[test]
1096    fn observe_call_filters_value() {
1097        let calldata = bytes!("c290d691");
1098        let mut t = tracker(
1099            calldata.clone(),
1100            None,
1101            expected(Some(U256::from(1)), None, None, 1, ExpectedCallType::NonCount),
1102        );
1103
1104        observe(&mut t, &calldata, Some(U256::from(2)), 0);
1105        observe(&mut t, &calldata, None, 0);
1106        assert_eq!(seen(&t, &calldata, None), 0);
1107
1108        observe(&mut t, &calldata, Some(U256::from(1)), 0);
1109        assert_eq!(seen(&t, &calldata, None), 1);
1110
1111        // An expected zero value does not match a call without a transfer value.
1112        let mut zero = tracker(
1113            calldata.clone(),
1114            None,
1115            expected(Some(U256::ZERO), None, None, 1, ExpectedCallType::NonCount),
1116        );
1117        observe(&mut zero, &calldata, None, 0);
1118        assert_eq!(seen(&zero, &calldata, None), 0);
1119        observe(&mut zero, &calldata, Some(U256::ZERO), 0);
1120        assert_eq!(seen(&zero, &calldata, None), 1);
1121
1122        // No expected value matches any transfer value.
1123        let mut any = tracker(
1124            calldata.clone(),
1125            None,
1126            expected(None, None, None, 1, ExpectedCallType::NonCount),
1127        );
1128        observe(&mut any, &calldata, Some(U256::from(5)), 0);
1129        assert_eq!(seen(&any, &calldata, None), 1);
1130    }
1131
1132    #[test]
1133    fn observe_call_filters_gas_and_min_gas() {
1134        let calldata = bytes!("771602f7");
1135        let mut gas = tracker(
1136            calldata.clone(),
1137            None,
1138            expected(None, Some(25_000), None, 1, ExpectedCallType::NonCount),
1139        );
1140        observe(&mut gas, &calldata, None, 24_999);
1141        observe(&mut gas, &calldata, None, 25_001);
1142        assert_eq!(seen(&gas, &calldata, None), 0);
1143        observe(&mut gas, &calldata, None, 25_000);
1144        assert_eq!(seen(&gas, &calldata, None), 1);
1145
1146        let mut min_gas = tracker(
1147            calldata.clone(),
1148            None,
1149            expected(None, None, Some(50_000), 1, ExpectedCallType::NonCount),
1150        );
1151        observe(&mut min_gas, &calldata, None, 49_999);
1152        assert_eq!(seen(&min_gas, &calldata, None), 0);
1153        observe(&mut min_gas, &calldata, None, 50_000);
1154        observe(&mut min_gas, &calldata, None, 60_000);
1155        assert_eq!(seen(&min_gas, &calldata, None), 2);
1156    }
1157
1158    #[test]
1159    fn observe_call_filters_scheme() {
1160        let calldata = bytes!("771602f7");
1161        let mut t = tracker(
1162            calldata.clone(),
1163            Some(ExpectedCallScheme::DelegateCall),
1164            expected(None, None, None, 1, ExpectedCallType::NonCount),
1165        );
1166
1167        observe_call(t.get_mut(&TARGET).unwrap(), &calldata, None, 0, ExpectedCallScheme::Call);
1168        assert_eq!(seen(&t, &calldata, Some(ExpectedCallScheme::DelegateCall)), 0);
1169
1170        observe_call(
1171            t.get_mut(&TARGET).unwrap(),
1172            &calldata,
1173            None,
1174            0,
1175            ExpectedCallScheme::DelegateCall,
1176        );
1177        assert_eq!(seen(&t, &calldata, Some(ExpectedCallScheme::DelegateCall)), 1);
1178    }
1179
1180    #[test]
1181    fn first_unmet_call_compares_counts() {
1182        let calldata = bytes!("771602f7");
1183        let mut count =
1184            tracker(calldata.clone(), None, expected(None, None, None, 2, ExpectedCallType::Count));
1185        let mut non_count =
1186            tracker(calldata, None, expected(None, None, None, 2, ExpectedCallType::NonCount));
1187
1188        for seen in [1, 3] {
1189            count.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = seen;
1190            assert!(first_unmet_call(&count, true).is_some(), "count with {seen} calls");
1191        }
1192        count.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = 2;
1193        assert_eq!(first_unmet_call(&count, true), None);
1194
1195        non_count.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = 1;
1196        assert!(first_unmet_call(&non_count, true).is_some());
1197        for seen in [2, 3] {
1198            non_count.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = seen;
1199            assert_eq!(first_unmet_call(&non_count, true), None, "non-count with {seen} calls");
1200        }
1201    }
1202
1203    #[test]
1204    fn first_unmet_call_reports_smallest_unmet_key() {
1205        let low = address!("0000000000000000000000000000000000000001");
1206        let high = address!("0000000000000000000000000000000000000002");
1207        let ordered = [
1208            (low, bytes!("01"), None, ""),
1209            (low, bytes!("01"), Some(ExpectedCallScheme::Call), ", call type Call"),
1210            (low, bytes!("01"), Some(ExpectedCallScheme::CallCode), ", call type CallCode"),
1211            (low, bytes!("01"), Some(ExpectedCallScheme::DelegateCall), ", call type DelegateCall"),
1212            (low, bytes!("01"), Some(ExpectedCallScheme::StaticCall), ", call type StaticCall"),
1213            (low, bytes!("02"), None, ""),
1214            (high, bytes!("00"), None, ""),
1215            (high, bytes!("01"), None, ""),
1216        ];
1217
1218        for offset in 0..ordered.len() {
1219            let mut t = ExpectedCallTracker::default();
1220            // A satisfied expectation must not hide a later failure.
1221            t.entry(Address::ZERO).or_default().insert(
1222                (Bytes::new(), None),
1223                (expected(None, None, None, 1, ExpectedCallType::NonCount), 1),
1224            );
1225            for index in (0..ordered.len()).rev() {
1226                let (address, calldata, scheme, _) = &ordered[(index + offset) % ordered.len()];
1227                t.entry(*address).or_default().insert(
1228                    (calldata.clone(), *scheme),
1229                    (expected(None, None, None, 1, ExpectedCallType::NonCount), 0),
1230                );
1231            }
1232
1233            for (address, calldata, scheme, suffix) in &ordered {
1234                assert_eq!(
1235                    first_unmet_call(&t, true).unwrap(),
1236                    format!(
1237                        "expected call to {address} with data {}{suffix} to be called 1 time, \
1238                         but was called 0 times",
1239                        hex::encode_prefixed(calldata),
1240                    ),
1241                );
1242                t.get_mut(address).unwrap().remove(&(calldata.clone(), *scheme));
1243            }
1244            assert_eq!(first_unmet_call(&t, true), None);
1245        }
1246    }
1247
1248    #[test]
1249    fn first_unmet_call_message() {
1250        let calldata = bytes!("771602f7");
1251        let mut t = tracker(
1252            calldata.clone(),
1253            Some(ExpectedCallScheme::DelegateCall),
1254            expected(Some(U256::from(1)), Some(2), Some(3), 2, ExpectedCallType::Count),
1255        );
1256        t.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = 1;
1257
1258        assert_eq!(
1259            first_unmet_call(&t, true).unwrap(),
1260            "expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f7, \
1261             value 1, gas 2, minimum gas 3, call type DelegateCall to be called 2 times, \
1262             but was called 1 time"
1263        );
1264        assert_eq!(
1265            first_unmet_call(&t, false).unwrap(),
1266            "expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f7, \
1267             value 1, gas 2, minimum gas 3, call type DelegateCall to be called 2 times, \
1268             but the call reverted instead; ensure you're testing the happy path when using \
1269             `expectCall`"
1270        );
1271
1272        let single =
1273            tracker(calldata, None, expected(None, None, None, 1, ExpectedCallType::NonCount));
1274        assert_eq!(
1275            first_unmet_call(&single, true).unwrap(),
1276            "expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f7 \
1277             to be called 1 time, but was called 0 times"
1278        );
1279    }
1280
1281    #[test]
1282    fn observe_create_converts_the_scheme_only_for_a_matching_deployer() {
1283        let bytecode = bytes!("6080");
1284        let mut expected_creates = vec![ExpectedCreate {
1285            deployer: Address::ZERO,
1286            bytecode: bytecode.clone(),
1287            create_scheme: CreateScheme::Create,
1288        }];
1289
1290        observe_create(&mut expected_creates, TARGET, || unreachable!(), &bytecode);
1291        assert_eq!(expected_creates.len(), 1);
1292
1293        observe_create(&mut expected_creates, Address::ZERO, || CreateScheme::Create, &bytecode);
1294        assert!(expected_creates.is_empty());
1295    }
1296
1297    #[test]
1298    fn internal_expect_revert_waits_for_failure_before_root() {
1299        let expected_revert = ExpectedRevert {
1300            reason: None,
1301            depth: 1,
1302            kind: ExpectedRevertKind::Default,
1303            partial_match: false,
1304            reverter: None,
1305            reverted_by: None,
1306            max_depth: 1,
1307            count: 1,
1308            actual_count: 0,
1309        };
1310
1311        assert!(expected_revert.needs_processing(false, true, 1, true));
1312        assert!(!expected_revert.needs_processing(false, false, 1, true));
1313    }
1314}