1use ethers_contract_derive::{EthAbiCodec, EthAbiType};
2use ethers_core::{
3 abi::{AbiDecode, AbiEncode, AbiError, AbiType, ParamType},
4 types::{transaction::eip2718::TypedTransaction, Address, BlockId, Bytes, NameOrAddress, U256},
5};
6use ethers_providers::Middleware;
7use once_cell::sync::Lazy;
8use std::{
9 fmt::{self, Debug},
10 marker::PhantomData,
11 ops::Deref,
12};
13
14pub use ethers_core;
15pub use once_cell;
16
17#[derive(Debug, thiserror::Error)]
18pub enum Error<M: Middleware> {
19 #[error(transparent)]
20 Middleware(M::Error),
21 #[error(transparent)]
22 Abi(#[from] AbiError),
23}
24
25#[derive(Clone, Copy)]
26pub struct Method<A, R> {
27 args: A,
28 vtable: &'static MethodVTable,
29 _p: PhantomData<R>,
30}
31
32pub struct MethodVTable {
33 pub name: &'static str,
34 pub selector: Lazy<[u8; 4]>,
35 pub debug_args: unsafe fn(*const (), &mut fmt::Formatter<'_>) -> fmt::Result,
36}
37
38impl<A: fmt::Debug, R> fmt::Debug for Method<A, R> {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 struct Args<'a, A> {
41 args: &'a A,
42 debug: unsafe fn(*const (), &mut fmt::Formatter<'_>) -> fmt::Result,
43 }
44 impl<'a, A> fmt::Debug for Args<'a, A> {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 unsafe { (self.debug)(self.args as *const A as *const (), f) }
47 }
48 }
49 f.debug_struct("Method")
50 .field("selector", &hex::encode(self.vtable.selector.deref()))
51 .field(
52 "args",
53 &Args {
54 args: &self.args,
55 debug: self.vtable.debug_args,
56 },
57 )
58 .field("_name", &self.vtable.name)
59 .field("_p", &self._p)
60 .finish()
61 }
62}
63
64impl<A, R> Method<A, R> {
65 pub fn new(vtable: &'static MethodVTable, args: A) -> Self {
66 Self {
67 args,
68 vtable,
69 _p: PhantomData,
70 }
71 }
72
73 pub fn tx(self) -> MethodTx<A, R> {
74 MethodTx {
75 method: self,
76 tx: Default::default(),
77 }
78 }
79
80 pub fn call(self, to: Address, op: Operation) -> MethodCall<A, R> {
81 MethodCall {
82 method: self,
83 to,
84 op,
85 required: true,
86 value: U256::zero(),
87 }
88 }
89
90 pub fn encode_args(self) -> Vec<u8>
91 where
92 A: AbiEncode,
93 {
94 [self.vtable.selector.to_vec(), self.args.encode()].concat()
95 }
96}
97
98#[derive(Debug, Clone)]
99pub struct MethodTx<A, R> {
100 method: Method<A, R>,
101 tx: TypedTransaction,
102}
103
104impl<A, R> MethodTx<A, R> {
105 pub fn to(mut self, to: impl Into<NameOrAddress>) -> Self {
106 self.tx.set_to(to);
107 self
108 }
109
110 pub fn from(mut self, from: Address) -> Self {
111 self.tx.set_from(from);
112 self
113 }
114
115 pub async fn call<M: Middleware>(
116 mut self,
117 provider: &M,
118 block: Option<BlockId>,
119 ) -> Result<R, Error<M>>
120 where
121 A: AbiEncode + fmt::Debug,
122 R: AbiDecode + fmt::Debug,
123 {
124 let data = self.method.encode_args();
125 self.tx.set_data(data.into());
126 let data = provider
127 .call(&self.tx, block)
128 .await
129 .map_err(Error::Middleware)?;
130 Ok(AbiDecode::decode(data)?)
131 }
132
133 pub async fn estimate_gas<M: Middleware>(
134 mut self,
135 provider: &M,
136 block: Option<BlockId>,
137 ) -> Result<U256, Error<M>>
138 where
139 A: AbiEncode,
140 {
141 let data = self.method.encode_args();
142 self.tx.set_data(data.into());
143 provider
144 .estimate_gas(&self.tx, block)
145 .await
146 .map_err(Error::Middleware)
147 }
148}
149
150#[derive(Debug, Clone, Copy, EthAbiCodec, EthAbiType)]
151pub enum Operation {
152 Call,
153 DelegateCall,
154}
155
156impl AbiType for Operation {
157 fn param_type() -> ParamType {
158 <u8 as AbiType>::param_type()
159 }
160}
161
162#[derive(Debug, Clone, Copy)]
163pub struct MethodCall<A, R> {
164 pub method: Method<A, R>,
165 pub required: bool,
166 pub op: Operation,
167 pub to: Address,
168 pub value: U256,
169}
170
171impl<A, R> MethodCall<A, R> {
172 pub fn value(mut self, value: U256) -> Self {
173 self.value = value;
174 self
175 }
176
177 pub fn into_raw(self) -> RawCall
178 where
179 A: AbiEncode,
180 {
181 RawCall {
182 required: self.required,
183 op: self.op,
184 to: self.to,
185 value: self.value,
186 data: self.method.encode_args().into(),
187 }
188 }
189}
190
191#[derive(Debug, Clone, EthAbiCodec, EthAbiType)]
192pub struct RawCall {
193 pub op: Operation,
194 pub required: bool,
195 pub to: Address,
196 pub value: U256,
197 pub data: Bytes,
198}
199
200#[derive(Debug, Clone, EthAbiCodec, EthAbiType)]
201pub struct RawResult {
202 pub success: bool,
203 pub data: Bytes,
204}
205
206#[derive(Debug, Default, Clone, Copy)]
207pub struct Zst;
208
209impl AbiEncode for Zst {
210 fn encode(self) -> Vec<u8> {
211 vec![]
212 }
213}
214
215impl AbiDecode for Zst {
216 fn decode(_: impl AsRef<[u8]>) -> Result<Self, AbiError> {
217 Ok(Zst)
218 }
219}
220
221#[macro_export]
222macro_rules! impl_method {
223 ($alias:ident, $($vis: vis,)? $name:expr, $return_type:ty, $($arg_name:ident: $arg_type:ty),+) => {
224 #[allow(unused, clippy::too_many_arguments)]
225 $($vis)? fn $alias($($arg_name: $arg_type),+) -> $crate::Method<($($arg_type),+,), $return_type> {
226 use $crate::{
227 ethers_core::abi::{short_signature, AbiType},
228 once_cell::sync::Lazy,
229 Method, MethodVTable,
230 };
231 unsafe fn debug_args(args: *const (), f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 let ( $($arg_name),+ ,) = &*(args as *const ($($arg_type),+,));
233 f.debug_struct("Args")
234 $(.field(stringify!($arg_name), $arg_name))+
235 .finish()
236 }
237 static VTABLE: MethodVTable = MethodVTable {
238 selector: Lazy::new(|| {
239 short_signature($name, &[$(<$arg_type as AbiType>::param_type()),+])
240 }),
241 debug_args,
242 name: $name
243 };
244 Method::new(&VTABLE, ($($arg_name),+,))
245 }
246 };
247
248 ($alias:ident, $($vis: vis,)? $name:expr, $return_type:ty) => {
249 #[allow(unused)]
250 $($vis)? fn $alias() -> $crate::Method<$crate::Zst, $return_type> {
251 use $crate::{
252 ethers_core::abi::{short_signature, AbiType},
253 once_cell::sync::Lazy,
254 Method, MethodVTable, Zst
255 };
256 fn debug_args(_args: *const (), f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
257 f.debug_struct("Args").finish()
258 }
259 static VTABLE: MethodVTable = MethodVTable {
260 selector: Lazy::new(|| short_signature($name, &[])),
261 debug_args,
262 name: $name
263 };
264 Method::new(&VTABLE, Zst)
265 }
266 };
267}
268
269impl_method!(
270 multicall,
271 pub,
272 "multicall",
273 (U256, Vec<RawResult>),
274 calls: Vec<RawCall>
275);
276
277#[derive(Clone, Debug, Default)]
278pub struct Multicall<C> {
279 calls: C,
280 tx: TypedTransaction,
281}
282
283impl<C: Calls> Multicall<C> {
284 pub fn new(calls: C) -> Self {
285 Self {
286 calls,
287 tx: Default::default(),
288 }
289 }
290
291 pub fn to(mut self, to: impl Into<NameOrAddress>) -> Self {
292 self.tx.set_to(to);
293 self
294 }
295
296 pub fn from(mut self, from: Address) -> Self {
297 self.tx.set_from(from);
298 self
299 }
300
301 pub async fn estimate_gas<P: Middleware>(
302 mut self,
303 provider: &P,
304 block: Option<BlockId>,
305 ) -> Result<U256, P::Error> {
306 let calls = self.calls.encode();
307 let data = multicall(calls).encode_args();
308 self.tx.set_data(data.into());
309 provider.estimate_gas(&self.tx, block).await
310 }
311
312 pub async fn call<P: Middleware>(
313 mut self,
314 provider: &P,
315 block: Option<BlockId>,
316 ) -> Result<(U256, C::Results), Error<P>> {
317 let calls = self.calls.encode();
318 let value = calls
319 .iter()
320 .fold(U256::zero(), |value, call| value + call.value);
321 let data = multicall(calls).encode_args();
322 self.tx.set_data(data.into());
323 self.tx.set_value(value);
324 let data = provider
325 .call(&self.tx, block)
326 .await
327 .map_err(Error::Middleware)?;
328 let (gas_used, results): (U256, Vec<RawResult>) = AbiDecode::decode(data)?;
329 Ok((gas_used, C::decode(results)?))
330 }
331}
332
333pub trait Calls: fmt::Debug {
334 type Results;
335 fn encode(self) -> Vec<RawCall>;
336 fn decode(results: Vec<RawResult>) -> Result<Self::Results, AbiError>
337 where
338 Self: Sized;
339}
340
341impl Calls for Vec<RawCall> {
342 type Results = Vec<RawResult>;
343
344 fn encode(self) -> Vec<RawCall> {
345 self
346 }
347
348 fn decode(results: Vec<RawResult>) -> Result<Self::Results, AbiError> {
349 Ok(results)
350 }
351}
352
353macro_rules! impl_tuples {
354 ($no0:tt : ($a0:ident, $r0:ident), $($no:tt : ($a:ident, $r:ident) ),+) => {
355 impl<
356 $a0: AbiEncode + fmt::Debug,
357 $r0: AbiDecode + fmt::Debug,
358 $( $a: AbiEncode + fmt::Debug, $r: AbiDecode + fmt::Debug ),+
359 > Calls for ( MethodCall<$a0, $r0>, $( MethodCall<$a, $r>, )+ )
360 {
361 type Results = ( $r0, $( $r, )+ );
362
363 fn encode(self) -> Vec<RawCall> {
364 let mut raw_calls = vec![self.$no0.into_raw(), $(self.$no.into_raw()),+];
365 raw_calls.reverse();
366 raw_calls
367 }
368
369 fn decode(mut results: Vec<RawResult>) -> Result<Self::Results, AbiError> {
370 Ok((
371 $r0::decode(results.pop().unwrap().data)?,
372 $($r::decode(results.pop().unwrap().data)?),+
373 ))
374 }
375 }
376 impl_tuples!($($no : ($a, $r) ),+);
377 };
378
379 ($no0:tt : ($a0:ident, $r0:ident)) => {
380 impl<
381 $a0: AbiEncode + fmt::Debug,
382 $r0: AbiDecode + fmt::Debug,
383 > Calls for (MethodCall<$a0, $r0>,)
384 {
385 type Results = ($r0,);
386
387 fn encode(self) -> Vec<RawCall> {
388 vec![self.$no0.into_raw()]
389 }
390
391 fn decode(mut results: Vec<RawResult>) -> Result<Self::Results, AbiError> {
392 Ok((
393 $r0::decode(results.pop().unwrap().data)?,
394 ))
395 }
396 }
397 };
398}
399
400impl_tuples!(
401 11: (A11, R11),
402 10: (A10, R10),
403 9: (A9, R9),
404 8: (A8, R8),
405 7: (A7, R7),
406 6: (A6, R6),
407 5: (A5, R5),
408 4: (A4, R4),
409 3: (A3, R3),
410 2: (A2, R2),
411 1: (A1, R1),
412 0: (A0, R0)
413);
414
415#[cfg(test)]
416mod test {
417 use super::*;
418
419 #[test]
420 fn test_args_debug() {
421 impl_method!(nonce, pub, "nonce", Zst);
422
423 let method = multicall(vec![]);
424 dbg!(&method);
425
426 let method = nonce();
427 dbg!(&method);
428 }
429}