ethers_method/
lib.rs

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}