1use alloy::primitives::{Address, Bytes, U256};
4use alloy::sol_types::SolCall;
5use std::future::Future;
6
7use super::Operation;
8use crate::error::Result;
9use crate::simulation::SimulationResult;
10
11pub trait CallBuilder: Sized {
16 fn calls_mut(&mut self) -> &mut Vec<Call>;
18
19 fn calls(&self) -> &Vec<Call>;
21
22 fn add_typed<C: SolCall + Clone>(mut self, to: Address, call: C) -> Self {
24 let typed_call = TypedCall::new(to, call);
25 self.calls_mut().push(Call::new(
26 typed_call.to(),
27 typed_call.value,
28 typed_call.data(),
29 ));
30 self
31 }
32
33 fn add_typed_with_value<C: SolCall + Clone>(
35 mut self,
36 to: Address,
37 call: C,
38 value: U256,
39 ) -> Self {
40 let typed_call = TypedCall::new(to, call).with_value(value);
41 self.calls_mut().push(Call::new(
42 typed_call.to(),
43 typed_call.value,
44 typed_call.data(),
45 ));
46 self
47 }
48
49 fn add_raw(mut self, to: Address, value: U256, data: impl Into<Bytes>) -> Self {
51 self.calls_mut().push(Call::new(to, value, data));
52 self
53 }
54
55 fn add(mut self, call: impl SafeCall) -> Self {
57 self.calls_mut().push(Call {
58 to: call.to(),
59 value: call.value(),
60 data: call.data(),
61 operation: call.operation(),
62 gas_limit: None,
63 });
64 self
65 }
66
67 fn with_gas_limit(self, gas_limit: u64) -> Self;
75
76 fn call_count(&self) -> usize {
78 self.calls().len()
79 }
80
81 fn simulate(self) -> impl Future<Output = Result<Self>> + Send;
90
91 fn simulation_result(&self) -> Option<&SimulationResult>;
93
94 fn simulation_success(self) -> Result<Self>;
105}
106
107pub trait SafeCall {
109 fn to(&self) -> Address;
111
112 fn value(&self) -> U256;
114
115 fn data(&self) -> Bytes;
117
118 fn operation(&self) -> Operation;
120}
121
122#[derive(Debug, Clone)]
124pub struct Call {
125 pub to: Address,
127 pub value: U256,
129 pub data: Bytes,
131 pub operation: Operation,
133 pub gas_limit: Option<u64>,
135}
136
137impl Call {
138 pub fn new(to: Address, value: U256, data: impl Into<Bytes>) -> Self {
140 Self {
141 to,
142 value,
143 data: data.into(),
144 operation: Operation::Call,
145 gas_limit: None,
146 }
147 }
148
149 pub fn call(to: Address, data: impl Into<Bytes>) -> Self {
151 Self::new(to, U256::ZERO, data)
152 }
153
154 pub fn delegate_call(to: Address, data: impl Into<Bytes>) -> Self {
156 Self {
157 to,
158 value: U256::ZERO,
159 data: data.into(),
160 operation: Operation::DelegateCall,
161 gas_limit: None,
162 }
163 }
164
165 pub fn with_operation(mut self, operation: Operation) -> Self {
167 self.operation = operation;
168 self
169 }
170
171 pub fn with_value(mut self, value: U256) -> Self {
173 self.value = value;
174 self
175 }
176
177 pub fn with_gas_limit(mut self, gas_limit: u64) -> Self {
179 self.gas_limit = Some(gas_limit);
180 self
181 }
182}
183
184impl SafeCall for Call {
185 fn to(&self) -> Address {
186 self.to
187 }
188
189 fn value(&self) -> U256 {
190 self.value
191 }
192
193 fn data(&self) -> Bytes {
194 self.data.clone()
195 }
196
197 fn operation(&self) -> Operation {
198 self.operation
199 }
200}
201
202#[derive(Debug, Clone)]
204pub struct TypedCall<C: SolCall> {
205 pub to: Address,
207 pub value: U256,
209 pub call: C,
211 pub operation: Operation,
213}
214
215impl<C: SolCall> TypedCall<C> {
216 pub fn new(to: Address, call: C) -> Self {
218 Self {
219 to,
220 value: U256::ZERO,
221 call,
222 operation: Operation::Call,
223 }
224 }
225
226 pub fn with_value(mut self, value: U256) -> Self {
228 self.value = value;
229 self
230 }
231
232 pub fn with_operation(mut self, operation: Operation) -> Self {
234 self.operation = operation;
235 self
236 }
237}
238
239impl<C: SolCall + Clone> SafeCall for TypedCall<C> {
240 fn to(&self) -> Address {
241 self.to
242 }
243
244 fn value(&self) -> U256 {
245 self.value
246 }
247
248 fn data(&self) -> Bytes {
249 self.call.abi_encode().into()
250 }
251
252 fn operation(&self) -> Operation {
253 self.operation
254 }
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260 use alloy::primitives::address;
261
262 #[test]
263 fn test_call_new() {
264 let to = address!("0x1234567890123456789012345678901234567890");
265 let value = U256::from(1000);
266 let data = Bytes::from(vec![0x01, 0x02, 0x03]);
267
268 let call = Call::new(to, value, data.clone());
269
270 assert_eq!(call.to(), to);
271 assert_eq!(call.value(), value);
272 assert_eq!(call.data(), data);
273 assert_eq!(call.operation(), Operation::Call);
274 }
275
276 #[test]
277 fn test_call_delegate() {
278 let to = address!("0x1234567890123456789012345678901234567890");
279 let data = Bytes::from(vec![0x01, 0x02, 0x03]);
280
281 let call = Call::delegate_call(to, data.clone());
282
283 assert_eq!(call.to(), to);
284 assert_eq!(call.value(), U256::ZERO);
285 assert_eq!(call.data(), data);
286 assert_eq!(call.operation(), Operation::DelegateCall);
287 }
288}