1use crate::{Cheatcode, Cheatcodes, CheatsCtxt, Result, Vm::*};
2use alloy_primitives::{Address, Bytes, U256};
3use revm::{
4 bytecode::Bytecode,
5 context::{ContextTr, JournalTr},
6 interpreter::InstructionResult,
7};
8use std::{cmp::Ordering, collections::VecDeque};
9
10#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
12pub struct MockCallDataContext {
13 pub calldata: Bytes,
15 pub value: Option<U256>,
17}
18
19#[derive(Clone, Debug)]
21pub struct MockCallReturnData {
22 pub ret_type: InstructionResult,
24 pub data: Bytes,
26}
27
28impl PartialOrd for MockCallDataContext {
29 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
30 Some(self.cmp(other))
31 }
32}
33
34impl Ord for MockCallDataContext {
35 fn cmp(&self, other: &Self) -> Ordering {
36 self.calldata.cmp(&other.calldata).reverse().then(self.value.cmp(&other.value).reverse())
42 }
43}
44
45impl Cheatcode for clearMockedCallsCall {
46 fn apply(&self, state: &mut Cheatcodes) -> Result {
47 let Self {} = self;
48 state.mocked_calls = Default::default();
49 Ok(Default::default())
50 }
51}
52
53impl Cheatcode for mockCall_0Call {
54 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
55 let Self { callee, data, returnData } = self;
56 let _ = make_acc_non_empty(callee, ccx)?;
57
58 mock_call(ccx.state, callee, data, None, returnData, InstructionResult::Return);
59 Ok(Default::default())
60 }
61}
62
63impl Cheatcode for mockCall_1Call {
64 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
65 let Self { callee, msgValue, data, returnData } = self;
66 let _ = make_acc_non_empty(callee, ccx)?;
67
68 mock_call(ccx.state, callee, data, Some(msgValue), returnData, InstructionResult::Return);
69 Ok(Default::default())
70 }
71}
72
73impl Cheatcode for mockCall_2Call {
74 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
75 let Self { callee, data, returnData } = self;
76 let _ = make_acc_non_empty(callee, ccx)?;
77
78 mock_call(
79 ccx.state,
80 callee,
81 &Bytes::from(*data),
82 None,
83 returnData,
84 InstructionResult::Return,
85 );
86 Ok(Default::default())
87 }
88}
89
90impl Cheatcode for mockCall_3Call {
91 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
92 let Self { callee, msgValue, data, returnData } = self;
93 let _ = make_acc_non_empty(callee, ccx)?;
94
95 mock_call(
96 ccx.state,
97 callee,
98 &Bytes::from(*data),
99 Some(msgValue),
100 returnData,
101 InstructionResult::Return,
102 );
103 Ok(Default::default())
104 }
105}
106
107impl Cheatcode for mockCalls_0Call {
108 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
109 let Self { callee, data, returnData } = self;
110 let _ = make_acc_non_empty(callee, ccx)?;
111
112 mock_calls(ccx.state, callee, data, None, returnData, InstructionResult::Return);
113 Ok(Default::default())
114 }
115}
116
117impl Cheatcode for mockCalls_1Call {
118 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
119 let Self { callee, msgValue, data, returnData } = self;
120 let _ = make_acc_non_empty(callee, ccx)?;
121
122 mock_calls(ccx.state, callee, data, Some(msgValue), returnData, InstructionResult::Return);
123 Ok(Default::default())
124 }
125}
126
127impl Cheatcode for mockCallRevert_0Call {
128 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
129 let Self { callee, data, revertData } = self;
130 let _ = make_acc_non_empty(callee, ccx)?;
131
132 mock_call(ccx.state, callee, data, None, revertData, InstructionResult::Revert);
133 Ok(Default::default())
134 }
135}
136
137impl Cheatcode for mockCallRevert_1Call {
138 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
139 let Self { callee, msgValue, data, revertData } = self;
140 let _ = make_acc_non_empty(callee, ccx)?;
141
142 mock_call(ccx.state, callee, data, Some(msgValue), revertData, InstructionResult::Revert);
143 Ok(Default::default())
144 }
145}
146
147impl Cheatcode for mockCallRevert_2Call {
148 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
149 let Self { callee, data, revertData } = self;
150 let _ = make_acc_non_empty(callee, ccx)?;
151
152 mock_call(
153 ccx.state,
154 callee,
155 &Bytes::from(*data),
156 None,
157 revertData,
158 InstructionResult::Revert,
159 );
160 Ok(Default::default())
161 }
162}
163
164impl Cheatcode for mockCallRevert_3Call {
165 fn apply_stateful(&self, ccx: &mut CheatsCtxt) -> Result {
166 let Self { callee, msgValue, data, revertData } = self;
167 let _ = make_acc_non_empty(callee, ccx)?;
168
169 mock_call(
170 ccx.state,
171 callee,
172 &Bytes::from(*data),
173 Some(msgValue),
174 revertData,
175 InstructionResult::Revert,
176 );
177 Ok(Default::default())
178 }
179}
180
181impl Cheatcode for mockFunctionCall {
182 fn apply(&self, state: &mut Cheatcodes) -> Result {
183 let Self { callee, target, data } = self;
184 state.mocked_functions.entry(*callee).or_default().insert(data.clone(), *target);
185
186 Ok(Default::default())
187 }
188}
189
190fn mock_call(
191 state: &mut Cheatcodes,
192 callee: &Address,
193 cdata: &Bytes,
194 value: Option<&U256>,
195 rdata: &Bytes,
196 ret_type: InstructionResult,
197) {
198 mock_calls(state, callee, cdata, value, std::slice::from_ref(rdata), ret_type)
199}
200
201fn mock_calls(
202 state: &mut Cheatcodes,
203 callee: &Address,
204 cdata: &Bytes,
205 value: Option<&U256>,
206 rdata_vec: &[Bytes],
207 ret_type: InstructionResult,
208) {
209 state.mocked_calls.entry(*callee).or_default().insert(
210 MockCallDataContext { calldata: cdata.clone(), value: value.copied() },
211 rdata_vec
212 .iter()
213 .map(|rdata| MockCallReturnData { ret_type, data: rdata.clone() })
214 .collect::<VecDeque<_>>(),
215 );
216}
217
218fn make_acc_non_empty(callee: &Address, ecx: &mut CheatsCtxt) -> Result {
221 let acc = ecx.journal_mut().load_account(*callee)?;
222
223 let empty_bytecode = acc.info.code.as_ref().is_none_or(Bytecode::is_empty);
224 if empty_bytecode {
225 let code = Bytecode::new_raw(Bytes::from_static(&[0u8]));
226 ecx.journal_mut().set_code(*callee, code);
227 }
228
229 Ok(Default::default())
230}