Skip to main content

foundry_cheatcodes/test/
expect.rs

1use std::fmt::{self, Display};
2
3use crate::{
4    Cheatcode, Cheatcodes, 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 = HashMap<(Bytes, Option<CallScheme>), (ExpectedCallData, u64)>;
36
37#[derive(Clone, Debug)]
38pub struct ExpectedCallData {
39    /// The expected value sent in the call
40    pub value: Option<U256>,
41    /// The expected gas supplied to the call
42    pub gas: Option<u64>,
43    /// The expected *minimum* gas supplied to the call
44    pub min_gas: Option<u64>,
45    /// The number of times the call is expected to be made.
46    /// If the type of call is `NonCount`, this is the lower bound for the number of calls
47    /// that must be seen.
48    /// If the type of call is `Count`, this is the exact number of calls that must be seen.
49    pub count: u64,
50    /// The type of expected call.
51    pub call_type: ExpectedCallType,
52}
53
54/// The type of expected call.
55#[derive(Clone, Debug, PartialEq, Eq)]
56pub enum ExpectedCallType {
57    /// The call is expected to be made at least once.
58    NonCount,
59    /// The exact number of calls expected.
60    Count,
61}
62
63/// The type of expected revert.
64#[derive(Clone, Debug)]
65pub enum ExpectedRevertKind {
66    /// Expects revert from the next non-cheatcode call.
67    Default,
68    /// Expects revert from the next cheatcode call.
69    ///
70    /// The `pending_processing` flag is used to track whether we have exited
71    /// `expectCheatcodeRevert` context or not.
72    /// We have to track it to avoid expecting `expectCheatcodeRevert` call to revert itself.
73    Cheatcode { pending_processing: bool },
74}
75
76#[derive(Clone, Debug)]
77pub struct ExpectedRevert {
78    /// The expected data returned by the revert, None being any.
79    pub reason: Option<Bytes>,
80    /// The depth at which the revert is expected.
81    pub depth: usize,
82    /// The type of expected revert.
83    pub kind: ExpectedRevertKind,
84    /// If true then only the first 4 bytes of expected data returned by the revert are checked.
85    pub partial_match: bool,
86    /// Contract expected to revert next call.
87    pub reverter: Option<Address>,
88    /// Address that reverted the call.
89    pub reverted_by: Option<Address>,
90    /// Max call depth reached during next call execution.
91    pub max_depth: usize,
92    /// Number of times this revert is expected.
93    pub count: u64,
94    /// Actual number of times this revert has been seen.
95    pub actual_count: u64,
96}
97
98#[derive(Clone, Debug)]
99pub struct ExpectedCreate {
100    /// The address that deployed the contract
101    pub deployer: Address,
102    /// Runtime bytecode of the contract
103    pub bytecode: Bytes,
104    /// Whether deployed with CREATE or CREATE2
105    pub create_scheme: CreateScheme,
106}
107
108#[derive(Clone, Debug)]
109pub enum CreateScheme {
110    Create,
111    Create2,
112}
113
114impl Display for CreateScheme {
115    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
116        match self {
117            Self::Create => write!(f, "CREATE"),
118            Self::Create2 => write!(f, "CREATE2"),
119        }
120    }
121}
122
123impl From<revm::context_interface::CreateScheme> for CreateScheme {
124    fn from(scheme: revm::context_interface::CreateScheme) -> Self {
125        match scheme {
126            revm::context_interface::CreateScheme::Create => Self::Create,
127            revm::context_interface::CreateScheme::Create2 { .. } => Self::Create2,
128            _ => unimplemented!("Unsupported create scheme"),
129        }
130    }
131}
132
133impl CreateScheme {
134    pub const fn eq(&self, create_scheme: Self) -> bool {
135        matches!(
136            (self, create_scheme),
137            (Self::Create, Self::Create) | (Self::Create2, Self::Create2 { .. })
138        )
139    }
140}
141
142impl Cheatcode for expectCall_0Call {
143    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
144        let Self { callee, data } = self;
145        expect_call(state, callee, data, None, None, None, None, 1, ExpectedCallType::NonCount)
146    }
147}
148
149impl Cheatcode for expectCall_1Call {
150    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
151        let Self { callee, data, count } = self;
152        expect_call(state, callee, data, None, None, None, None, *count, ExpectedCallType::Count)
153    }
154}
155
156impl Cheatcode for expectCall_2Call {
157    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
158        let Self { callee, msgValue, data } = self;
159        expect_call(
160            state,
161            callee,
162            data,
163            Some(msgValue),
164            None,
165            None,
166            None,
167            1,
168            ExpectedCallType::NonCount,
169        )
170    }
171}
172
173impl Cheatcode for expectCall_3Call {
174    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
175        let Self { callee, msgValue, data, count } = self;
176        expect_call(
177            state,
178            callee,
179            data,
180            Some(msgValue),
181            None,
182            None,
183            None,
184            *count,
185            ExpectedCallType::Count,
186        )
187    }
188}
189
190impl Cheatcode for expectCall_4Call {
191    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
192        let Self { callee, msgValue, gas, data } = self;
193        expect_call(
194            state,
195            callee,
196            data,
197            Some(msgValue),
198            Some(*gas),
199            None,
200            None,
201            1,
202            ExpectedCallType::NonCount,
203        )
204    }
205}
206
207impl Cheatcode for expectCall_5Call {
208    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
209        let Self { callee, msgValue, gas, data, count } = self;
210        expect_call(
211            state,
212            callee,
213            data,
214            Some(msgValue),
215            Some(*gas),
216            None,
217            None,
218            *count,
219            ExpectedCallType::Count,
220        )
221    }
222}
223
224impl Cheatcode for expectDelegateCallCall {
225    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
226        let Self { callee, data } = self;
227        expect_call(
228            state,
229            callee,
230            data,
231            None,
232            None,
233            None,
234            Some(CallScheme::DelegateCall),
235            1,
236            ExpectedCallType::NonCount,
237        )
238    }
239}
240
241impl Cheatcode for expectCallMinGas_0Call {
242    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
243        let Self { callee, msgValue, minGas, data } = self;
244        expect_call(
245            state,
246            callee,
247            data,
248            Some(msgValue),
249            None,
250            Some(*minGas),
251            None,
252            1,
253            ExpectedCallType::NonCount,
254        )
255    }
256}
257
258impl Cheatcode for expectCallMinGas_1Call {
259    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
260        let Self { callee, msgValue, minGas, data, count } = self;
261        expect_call(
262            state,
263            callee,
264            data,
265            Some(msgValue),
266            None,
267            Some(*minGas),
268            None,
269            *count,
270            ExpectedCallType::Count,
271        )
272    }
273}
274
275impl Cheatcode for expectEmit_0Call {
276    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
277        let Self { checkTopic1, checkTopic2, checkTopic3, checkData } = *self;
278        expect_emit(
279            ccx.state,
280            ccx.depth(),
281            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
282            None,
283            false,
284            1,
285        )
286    }
287}
288
289impl Cheatcode for expectEmit_1Call {
290    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
291        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;
292        expect_emit(
293            ccx.state,
294            ccx.depth(),
295            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
296            Some(emitter),
297            false,
298            1,
299        )
300    }
301}
302
303impl Cheatcode for expectEmit_2Call {
304    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
305        let Self {} = self;
306        expect_emit(ccx.state, ccx.depth(), [true; 5], None, false, 1)
307    }
308}
309
310impl Cheatcode for expectEmit_3Call {
311    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
312        let Self { emitter } = *self;
313        expect_emit(ccx.state, ccx.depth(), [true; 5], Some(emitter), false, 1)
314    }
315}
316
317impl Cheatcode for expectEmit_4Call {
318    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
319        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, count } = *self;
320        expect_emit(
321            ccx.state,
322            ccx.depth(),
323            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
324            None,
325            false,
326            count,
327        )
328    }
329}
330
331impl Cheatcode for expectEmit_5Call {
332    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
333        let Self { checkTopic1, checkTopic2, checkTopic3, checkData, emitter, count } = *self;
334        expect_emit(
335            ccx.state,
336            ccx.depth(),
337            [true, checkTopic1, checkTopic2, checkTopic3, checkData],
338            Some(emitter),
339            false,
340            count,
341        )
342    }
343}
344
345impl Cheatcode for expectEmit_6Call {
346    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
347        let Self { count } = *self;
348        expect_emit(ccx.state, ccx.depth(), [true; 5], None, false, count)
349    }
350}
351
352impl Cheatcode for expectEmit_7Call {
353    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
354        let Self { emitter, count } = *self;
355        expect_emit(ccx.state, ccx.depth(), [true; 5], Some(emitter), false, count)
356    }
357}
358
359impl Cheatcode for expectEmitAnonymous_0Call {
360    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
361        let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData } = *self;
362        expect_emit(
363            ccx.state,
364            ccx.depth(),
365            [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],
366            None,
367            true,
368            1,
369        )
370    }
371}
372
373impl Cheatcode for expectEmitAnonymous_1Call {
374    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
375        let Self { checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData, emitter } = *self;
376        expect_emit(
377            ccx.state,
378            ccx.depth(),
379            [checkTopic0, checkTopic1, checkTopic2, checkTopic3, checkData],
380            Some(emitter),
381            true,
382            1,
383        )
384    }
385}
386
387impl Cheatcode for expectEmitAnonymous_2Call {
388    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
389        let Self {} = self;
390        expect_emit(ccx.state, ccx.depth(), [true; 5], None, true, 1)
391    }
392}
393
394impl Cheatcode for expectEmitAnonymous_3Call {
395    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
396        let Self { emitter } = *self;
397        expect_emit(ccx.state, ccx.depth(), [true; 5], Some(emitter), true, 1)
398    }
399}
400
401impl Cheatcode for expectCreateCall {
402    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
403        let Self { bytecode, deployer } = self;
404        expect_create(state, bytecode.clone(), *deployer, CreateScheme::Create)
405    }
406}
407
408impl Cheatcode for expectCreate2Call {
409    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
410        let Self { bytecode, deployer } = self;
411        expect_create(state, bytecode.clone(), *deployer, CreateScheme::Create2)
412    }
413}
414
415impl Cheatcode for expectTip20LogoURIUpdatedCall {
416    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
417        let Self { token, updater, newLogoURI } = self;
418        expect_logo_uri_updated(ccx, token, updater, newLogoURI)
419    }
420}
421
422impl Cheatcode for expectKeychainVerifiedCall {
423    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
424        let Self { account, digest, signature } = self;
425        expect_keychain_verified(state, *account, *digest, signature.clone(), false)
426    }
427}
428
429impl Cheatcode for expectKeychainAdminVerifiedCall {
430    fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
431        let Self { account, digest, signature } = self;
432        expect_keychain_verified(state, *account, *digest, signature.clone(), true)
433    }
434}
435
436impl Cheatcode for expectLogoURIUpdatedCall {
437    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
438        let Self { token, updater, newLogoURI } = self;
439        expect_logo_uri_updated(ccx, token, updater, newLogoURI)
440    }
441}
442
443fn expect_keychain_verified<FEN: FoundryEvmNetwork>(
444    state: &mut Cheatcodes<FEN>,
445    account: Address,
446    digest: alloy_primitives::B256,
447    signature: Bytes,
448    admin: bool,
449) -> Result {
450    let calldata = if admin {
451        ISignatureVerifier::verifyKeychainAdminCall { account, hash: digest, signature }
452            .abi_encode()
453    } else {
454        ISignatureVerifier::verifyKeychainCall { account, hash: digest, signature }.abi_encode()
455    };
456    expect_call(
457        state,
458        &SIGNATURE_VERIFIER_ADDRESS,
459        &Bytes::from(calldata),
460        None,
461        None,
462        None,
463        None,
464        1,
465        ExpectedCallType::NonCount,
466    )
467}
468
469fn expect_logo_uri_updated<FEN: FoundryEvmNetwork>(
470    ccx: &mut CheatsCtxt<'_, '_, FEN>,
471    token: &Address,
472    updater: &Address,
473    new_logo_uri: &str,
474) -> Result {
475    let expected_emit = ExpectedEmit {
476        depth: ccx.depth(),
477        log: Some(RawLog::new_unchecked(
478            vec![keccak256("LogoURIUpdated(address,string)"), updater.into_word()],
479            new_logo_uri.abi_encode().into(),
480        )),
481        checks: [true, true, false, false, true],
482        address: Some(*token),
483        anonymous: false,
484        found: false,
485        count: 1,
486        mismatch_error: None,
487    };
488    ccx.state.expected_emits.push_back((expected_emit, Default::default()));
489    Ok(Default::default())
490}
491
492impl Cheatcode for expectRevert_0Call {
493    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
494        let Self {} = self;
495        expect_revert(ccx.state, None, ccx.depth(), false, false, None, 1)
496    }
497}
498
499impl Cheatcode for expectRevert_1Call {
500    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
501        let Self { revertData } = self;
502        expect_revert(ccx.state, Some(revertData.as_ref()), ccx.depth(), false, false, None, 1)
503    }
504}
505
506impl Cheatcode for expectRevert_2Call {
507    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
508        let Self { revertData } = self;
509        expect_revert(ccx.state, Some(revertData), ccx.depth(), false, false, None, 1)
510    }
511}
512
513impl Cheatcode for expectRevert_3Call {
514    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
515        let Self { reverter } = self;
516        expect_revert(ccx.state, None, ccx.depth(), false, false, Some(*reverter), 1)
517    }
518}
519
520impl Cheatcode for expectRevert_4Call {
521    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
522        let Self { revertData, reverter } = self;
523        expect_revert(
524            ccx.state,
525            Some(revertData.as_ref()),
526            ccx.depth(),
527            false,
528            false,
529            Some(*reverter),
530            1,
531        )
532    }
533}
534
535impl Cheatcode for expectRevert_5Call {
536    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
537        let Self { revertData, reverter } = self;
538        expect_revert(ccx.state, Some(revertData), ccx.depth(), false, false, Some(*reverter), 1)
539    }
540}
541
542impl Cheatcode for expectRevert_6Call {
543    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
544        let Self { count } = self;
545        expect_revert(ccx.state, None, ccx.depth(), false, false, None, *count)
546    }
547}
548
549impl Cheatcode for expectRevert_7Call {
550    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
551        let Self { revertData, count } = self;
552        expect_revert(ccx.state, Some(revertData.as_ref()), ccx.depth(), false, false, None, *count)
553    }
554}
555
556impl Cheatcode for expectRevert_8Call {
557    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
558        let Self { revertData, count } = self;
559        expect_revert(ccx.state, Some(revertData), ccx.depth(), false, false, None, *count)
560    }
561}
562
563impl Cheatcode for expectRevert_9Call {
564    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
565        let Self { reverter, count } = self;
566        expect_revert(ccx.state, None, ccx.depth(), false, false, Some(*reverter), *count)
567    }
568}
569
570impl Cheatcode for expectRevert_10Call {
571    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
572        let Self { revertData, reverter, count } = self;
573        expect_revert(
574            ccx.state,
575            Some(revertData.as_ref()),
576            ccx.depth(),
577            false,
578            false,
579            Some(*reverter),
580            *count,
581        )
582    }
583}
584
585impl Cheatcode for expectRevert_11Call {
586    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
587        let Self { revertData, reverter, count } = self;
588        expect_revert(
589            ccx.state,
590            Some(revertData),
591            ccx.depth(),
592            false,
593            false,
594            Some(*reverter),
595            *count,
596        )
597    }
598}
599
600impl Cheatcode for expectPartialRevert_0Call {
601    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
602        let Self { revertData } = self;
603        expect_revert(ccx.state, Some(revertData.as_ref()), ccx.depth(), false, true, None, 1)
604    }
605}
606
607impl Cheatcode for expectPartialRevert_1Call {
608    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
609        let Self { revertData, reverter } = self;
610        expect_revert(
611            ccx.state,
612            Some(revertData.as_ref()),
613            ccx.depth(),
614            false,
615            true,
616            Some(*reverter),
617            1,
618        )
619    }
620}
621
622impl Cheatcode for _expectCheatcodeRevert_0Call {
623    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
624        expect_revert(ccx.state, None, ccx.depth(), true, false, None, 1)
625    }
626}
627
628impl Cheatcode for _expectCheatcodeRevert_1Call {
629    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
630        let Self { revertData } = self;
631        expect_revert(ccx.state, Some(revertData.as_ref()), ccx.depth(), true, false, None, 1)
632    }
633}
634
635impl Cheatcode for _expectCheatcodeRevert_2Call {
636    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
637        let Self { revertData } = self;
638        expect_revert(ccx.state, Some(revertData), ccx.depth(), true, false, None, 1)
639    }
640}
641
642impl Cheatcode for expectSafeMemoryCall {
643    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
644        let Self { min, max } = *self;
645        expect_safe_memory(ccx.state, min, max, ccx.depth().try_into()?)
646    }
647}
648
649impl Cheatcode for stopExpectSafeMemoryCall {
650    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
651        let Self {} = self;
652        ccx.state.allowed_mem_writes.remove(&ccx.depth().try_into()?);
653        Ok(Default::default())
654    }
655}
656
657impl Cheatcode for expectSafeMemoryCallCall {
658    fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
659        let Self { min, max } = *self;
660        expect_safe_memory(ccx.state, min, max, (ccx.depth() + 1).try_into()?)
661    }
662}
663
664impl RevertParameters for ExpectedRevert {
665    fn reverter(&self) -> Option<Address> {
666        self.reverter
667    }
668
669    fn reason(&self) -> Option<&[u8]> {
670        self.reason.as_ref().map(|b| &***b)
671    }
672
673    fn partial_match(&self) -> bool {
674        self.partial_match
675    }
676}
677
678impl ExpectedRevert {
679    /// Returns whether a call ending at `depth`, at or above the expectation's depth, consumes
680    /// this expectation.
681    ///
682    /// With `internal_expect_revert` enabled, a same-depth revert can satisfy it, but it must not
683    /// be consumed by external calls that succeed (e.g. calls to non-contract addresses that
684    /// return `Stop` before Solidity's own revert).
685    pub(crate) const fn needs_processing(
686        &self,
687        cheatcode_call: bool,
688        call_failed: bool,
689        depth: usize,
690        internal_expect_revert: bool,
691    ) -> bool {
692        let went_deeper = self.max_depth > self.depth;
693        match self.kind {
694            ExpectedRevertKind::Default => {
695                // Cheatcode reverts propagate up; let the outer frame catch them.
696                if cheatcode_call {
697                    return false;
698                }
699                // Any failure satisfies the expectation.
700                if call_failed {
701                    return true;
702                }
703                // Traditional expectRevert: succeeded external call went deeper.
704                if !internal_expect_revert && went_deeper {
705                    return true;
706                }
707                // Test function returned: catch dangling expectations.
708                if depth == 0 {
709                    return true;
710                }
711                // Same-depth success with internal mode off is an error; with it on,
712                // keep waiting for the actual revert.
713                !internal_expect_revert
714            }
715            // `pending_processing == true` means we're in the `call_end` hook for
716            // `vm.expectCheatcodeRevert` and shouldn't expect a revert here.
717            ExpectedRevertKind::Cheatcode { pending_processing } => {
718                cheatcode_call && !pending_processing
719            }
720        }
721    }
722}
723
724/// Handles expected calls specified by the `expectCall` cheatcodes.
725///
726/// It can handle calls in two ways:
727/// - If the cheatcode was used with a `count` argument, it will expect the call to be made exactly
728///   `count` times. e.g. `vm.expectCall(address(0xc4f3), abi.encodeWithSelector(0xd34db33f), 4)`
729///   will expect the call to address(0xc4f3) with selector `0xd34db33f` to be made exactly 4 times.
730///   If the amount of calls is less or more than 4, the test will fail. Note that the `count`
731///   argument cannot be overwritten with another `vm.expectCall`. If this is attempted,
732///   `expectCall` will revert.
733/// - If the cheatcode was used without a `count` argument, it will expect the call to be made at
734///   least the amount of times the cheatcode was called. This means that `vm.expectCall` without a
735///   count argument can be called many times, but cannot be called with a `count` argument after it
736///   was called without one. If the latter happens, `expectCall` will revert. e.g
737///   `vm.expectCall(address(0xc4f3), abi.encodeWithSelector(0xd34db33f))` will expect the call to
738///   address(0xc4f3) and selector `0xd34db33f` to be made at least once. If the amount of calls is
739///   0, the test will fail. If the call is made more than once, the test will pass.
740#[expect(clippy::too_many_arguments)] // It is what it is
741fn expect_call<FEN: FoundryEvmNetwork>(
742    state: &mut Cheatcodes<FEN>,
743    target: &Address,
744    calldata: &Bytes,
745    value: Option<&U256>,
746    mut gas: Option<u64>,
747    mut min_gas: Option<u64>,
748    scheme: Option<CallScheme>,
749    count: u64,
750    call_type: ExpectedCallType,
751) -> Result {
752    let expecteds = state.expected_calls.entry(*target).or_default();
753
754    if let Some(val) = value
755        && *val > U256::ZERO
756    {
757        // If the value of the transaction is non-zero, the EVM adds a call stipend of 2300 gas
758        // to ensure that the basic fallback function can be called.
759        let positive_value_cost_stipend = 2300;
760        if let Some(gas) = &mut gas {
761            *gas += positive_value_cost_stipend;
762        }
763        if let Some(min_gas) = &mut min_gas {
764            *min_gas += positive_value_cost_stipend;
765        }
766    }
767
768    match call_type {
769        ExpectedCallType::Count => {
770            // Get the expected calls for this target.
771            // In this case, as we're using counted expectCalls, we should not be able to set them
772            // more than once.
773            let key = (calldata.clone(), scheme);
774            ensure!(!expecteds.contains_key(&key), "counted expected calls can only bet set once");
775            expecteds.insert(
776                key,
777                (ExpectedCallData { value: value.copied(), gas, min_gas, count, call_type }, 0),
778            );
779        }
780        ExpectedCallType::NonCount => {
781            // Check if the expected calldata exists.
782            // If it does, increment the count by one as we expect to see it one more time.
783            match expecteds.entry((calldata.clone(), scheme)) {
784                Entry::Occupied(mut entry) => {
785                    let (expected, _) = entry.get_mut();
786                    // Ensure we're not overwriting a counted expectCall.
787                    ensure!(
788                        expected.call_type == ExpectedCallType::NonCount,
789                        "cannot overwrite a counted expectCall with a non-counted expectCall"
790                    );
791                    expected.count += 1;
792                }
793                // If it does not exist, then create it.
794                Entry::Vacant(entry) => {
795                    entry.insert((
796                        ExpectedCallData { value: value.copied(), gas, min_gas, count, call_type },
797                        0,
798                    ));
799                }
800            }
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: CallScheme,
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<CallScheme>) -> u8 {
885    match scheme {
886        None => 0,
887        Some(CallScheme::Call) => 1,
888        Some(CallScheme::CallCode) => 2,
889        Some(CallScheme::DelegateCall) => 3,
890        Some(CallScheme::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<CallScheme>,
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(tracker: &ExpectedCallTracker, calldata: &Bytes, scheme: Option<CallScheme>) -> u64 {
1056        tracker[&TARGET][&(calldata.clone(), scheme)].1
1057    }
1058
1059    fn observe(tracker: &mut ExpectedCallTracker, input: &[u8], value: Option<U256>, gas: u64) {
1060        observe_call(tracker.get_mut(&TARGET).unwrap(), input, value, gas, CallScheme::Call);
1061    }
1062
1063    #[test]
1064    fn observe_call_matches_calldata_prefix() {
1065        let selector = bytes!("771602f7");
1066        let full = bytes!("771602f7aabb");
1067        let mut t = tracker(
1068            selector.clone(),
1069            None,
1070            expected(None, None, None, 1, ExpectedCallType::NonCount),
1071        );
1072        t.entry(TARGET).or_default().insert(
1073            (full.clone(), None),
1074            (expected(None, None, None, 1, ExpectedCallType::NonCount), 0),
1075        );
1076
1077        observe(&mut t, &full, None, 0);
1078        observe(&mut t, &selector, None, 0);
1079        observe(&mut t, &bytes!("12345678"), None, 0);
1080
1081        assert_eq!(seen(&t, &selector, None), 2);
1082        assert_eq!(seen(&t, &full, None), 1);
1083    }
1084
1085    #[test]
1086    fn observe_call_filters_value() {
1087        let calldata = bytes!("c290d691");
1088        let mut t = tracker(
1089            calldata.clone(),
1090            None,
1091            expected(Some(U256::from(1)), None, None, 1, ExpectedCallType::NonCount),
1092        );
1093
1094        observe(&mut t, &calldata, Some(U256::from(2)), 0);
1095        observe(&mut t, &calldata, None, 0);
1096        assert_eq!(seen(&t, &calldata, None), 0);
1097
1098        observe(&mut t, &calldata, Some(U256::from(1)), 0);
1099        assert_eq!(seen(&t, &calldata, None), 1);
1100
1101        // An expected zero value does not match a call without a transfer value.
1102        let mut zero = tracker(
1103            calldata.clone(),
1104            None,
1105            expected(Some(U256::ZERO), None, None, 1, ExpectedCallType::NonCount),
1106        );
1107        observe(&mut zero, &calldata, None, 0);
1108        assert_eq!(seen(&zero, &calldata, None), 0);
1109        observe(&mut zero, &calldata, Some(U256::ZERO), 0);
1110        assert_eq!(seen(&zero, &calldata, None), 1);
1111
1112        // No expected value matches any transfer value.
1113        let mut any = tracker(
1114            calldata.clone(),
1115            None,
1116            expected(None, None, None, 1, ExpectedCallType::NonCount),
1117        );
1118        observe(&mut any, &calldata, Some(U256::from(5)), 0);
1119        assert_eq!(seen(&any, &calldata, None), 1);
1120    }
1121
1122    #[test]
1123    fn observe_call_filters_gas_and_min_gas() {
1124        let calldata = bytes!("771602f7");
1125        let mut gas = tracker(
1126            calldata.clone(),
1127            None,
1128            expected(None, Some(25_000), None, 1, ExpectedCallType::NonCount),
1129        );
1130        observe(&mut gas, &calldata, None, 24_999);
1131        observe(&mut gas, &calldata, None, 25_001);
1132        assert_eq!(seen(&gas, &calldata, None), 0);
1133        observe(&mut gas, &calldata, None, 25_000);
1134        assert_eq!(seen(&gas, &calldata, None), 1);
1135
1136        let mut min_gas = tracker(
1137            calldata.clone(),
1138            None,
1139            expected(None, None, Some(50_000), 1, ExpectedCallType::NonCount),
1140        );
1141        observe(&mut min_gas, &calldata, None, 49_999);
1142        assert_eq!(seen(&min_gas, &calldata, None), 0);
1143        observe(&mut min_gas, &calldata, None, 50_000);
1144        observe(&mut min_gas, &calldata, None, 60_000);
1145        assert_eq!(seen(&min_gas, &calldata, None), 2);
1146    }
1147
1148    #[test]
1149    fn observe_call_filters_scheme() {
1150        let calldata = bytes!("771602f7");
1151        let mut t = tracker(
1152            calldata.clone(),
1153            Some(CallScheme::DelegateCall),
1154            expected(None, None, None, 1, ExpectedCallType::NonCount),
1155        );
1156
1157        observe_call(t.get_mut(&TARGET).unwrap(), &calldata, None, 0, CallScheme::Call);
1158        assert_eq!(seen(&t, &calldata, Some(CallScheme::DelegateCall)), 0);
1159
1160        observe_call(t.get_mut(&TARGET).unwrap(), &calldata, None, 0, CallScheme::DelegateCall);
1161        assert_eq!(seen(&t, &calldata, Some(CallScheme::DelegateCall)), 1);
1162    }
1163
1164    #[test]
1165    fn first_unmet_call_compares_counts() {
1166        let calldata = bytes!("771602f7");
1167        let mut count =
1168            tracker(calldata.clone(), None, expected(None, None, None, 2, ExpectedCallType::Count));
1169        let mut non_count =
1170            tracker(calldata, None, expected(None, None, None, 2, ExpectedCallType::NonCount));
1171
1172        for seen in [1, 3] {
1173            count.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = seen;
1174            assert!(first_unmet_call(&count, true).is_some(), "count with {seen} calls");
1175        }
1176        count.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = 2;
1177        assert_eq!(first_unmet_call(&count, true), None);
1178
1179        non_count.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = 1;
1180        assert!(first_unmet_call(&non_count, true).is_some());
1181        for seen in [2, 3] {
1182            non_count.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = seen;
1183            assert_eq!(first_unmet_call(&non_count, true), None, "non-count with {seen} calls");
1184        }
1185    }
1186
1187    #[test]
1188    fn first_unmet_call_reports_smallest_unmet_key() {
1189        let low = address!("0000000000000000000000000000000000000001");
1190        let high = address!("0000000000000000000000000000000000000002");
1191        let ordered = [
1192            (low, bytes!("01"), None, ""),
1193            (low, bytes!("01"), Some(CallScheme::Call), ", call type Call"),
1194            (low, bytes!("01"), Some(CallScheme::CallCode), ", call type CallCode"),
1195            (low, bytes!("01"), Some(CallScheme::DelegateCall), ", call type DelegateCall"),
1196            (low, bytes!("01"), Some(CallScheme::StaticCall), ", call type StaticCall"),
1197            (low, bytes!("02"), None, ""),
1198            (high, bytes!("00"), None, ""),
1199            (high, bytes!("01"), None, ""),
1200        ];
1201
1202        for offset in 0..ordered.len() {
1203            let mut t = ExpectedCallTracker::default();
1204            // A satisfied expectation must not hide a later failure.
1205            t.entry(Address::ZERO).or_default().insert(
1206                (Bytes::new(), None),
1207                (expected(None, None, None, 1, ExpectedCallType::NonCount), 1),
1208            );
1209            for index in (0..ordered.len()).rev() {
1210                let (address, calldata, scheme, _) = &ordered[(index + offset) % ordered.len()];
1211                t.entry(*address).or_default().insert(
1212                    (calldata.clone(), *scheme),
1213                    (expected(None, None, None, 1, ExpectedCallType::NonCount), 0),
1214                );
1215            }
1216
1217            for (address, calldata, scheme, suffix) in &ordered {
1218                assert_eq!(
1219                    first_unmet_call(&t, true).unwrap(),
1220                    format!(
1221                        "expected call to {address} with data {}{suffix} to be called 1 time, \
1222                         but was called 0 times",
1223                        hex::encode_prefixed(calldata),
1224                    ),
1225                );
1226                t.get_mut(address).unwrap().remove(&(calldata.clone(), *scheme));
1227            }
1228            assert_eq!(first_unmet_call(&t, true), None);
1229        }
1230    }
1231
1232    #[test]
1233    fn first_unmet_call_message() {
1234        let calldata = bytes!("771602f7");
1235        let mut t = tracker(
1236            calldata.clone(),
1237            Some(CallScheme::DelegateCall),
1238            expected(Some(U256::from(1)), Some(2), Some(3), 2, ExpectedCallType::Count),
1239        );
1240        t.get_mut(&TARGET).unwrap().values_mut().next().unwrap().1 = 1;
1241
1242        assert_eq!(
1243            first_unmet_call(&t, true).unwrap(),
1244            "expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f7, \
1245             value 1, gas 2, minimum gas 3, call type DelegateCall to be called 2 times, \
1246             but was called 1 time"
1247        );
1248        assert_eq!(
1249            first_unmet_call(&t, false).unwrap(),
1250            "expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f7, \
1251             value 1, gas 2, minimum gas 3, call type DelegateCall to be called 2 times, \
1252             but the call reverted instead; ensure you're testing the happy path when using \
1253             `expectCall`"
1254        );
1255
1256        let single =
1257            tracker(calldata, None, expected(None, None, None, 1, ExpectedCallType::NonCount));
1258        assert_eq!(
1259            first_unmet_call(&single, true).unwrap(),
1260            "expected call to 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f with data 0x771602f7 \
1261             to be called 1 time, but was called 0 times"
1262        );
1263    }
1264
1265    #[test]
1266    fn observe_create_converts_the_scheme_only_for_a_matching_deployer() {
1267        let bytecode = bytes!("6080");
1268        let mut expected_creates = vec![ExpectedCreate {
1269            deployer: Address::ZERO,
1270            bytecode: bytecode.clone(),
1271            create_scheme: CreateScheme::Create,
1272        }];
1273
1274        observe_create(&mut expected_creates, TARGET, || unreachable!(), &bytecode);
1275        assert_eq!(expected_creates.len(), 1);
1276
1277        observe_create(&mut expected_creates, Address::ZERO, || CreateScheme::Create, &bytecode);
1278        assert!(expected_creates.is_empty());
1279    }
1280
1281    #[test]
1282    fn internal_expect_revert_waits_for_failure_before_root() {
1283        let expected_revert = ExpectedRevert {
1284            reason: None,
1285            depth: 1,
1286            kind: ExpectedRevertKind::Default,
1287            partial_match: false,
1288            reverter: None,
1289            reverted_by: None,
1290            max_depth: 1,
1291            count: 1,
1292            actual_count: 0,
1293        };
1294
1295        assert!(expected_revert.needs_processing(false, true, 1, true));
1296        assert!(!expected_revert.needs_processing(false, false, 1, true));
1297    }
1298}