Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
Implement Multicall functionality for batched calls (#43)
Browse files Browse the repository at this point in the history
* Implement Multicall functionality for batched calls

* Documentation, some modifications as suggested in the review

* (Abigen) handle single input arg and set output irrespective of mutability

* implement send functionality and allow clearing calls

* Fix detokenization, dont require pre-processing anymore

* panic when more than supported number of calls are pushed

* add doc for panics in case of add_call

* (multicall) eth_balance support, update bindings

* refactor: move multicall to its own directory

* fix: add infura api key

* ci: ensure CI runs on PRs from forks

* test(multicall): re-use aggregate call

* contract: make multicall docs compile and remove redundant clones

* ci: add public etherscan API key so that forks don't get rate limited

* chore: adjust test contract naming

Co-authored-by: Georgios Konstantopoulos <[email protected]>
  • Loading branch information
roynalnaruto and gakonst authored Jul 3, 2020
1 parent 41998d6 commit a9bb98b
Show file tree
Hide file tree
Showing 12 changed files with 810 additions and 27 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
on: push
on: pull_request

name: Tests

# set for fetching ABIs for abigen from etherscan
# Yeah I know it's bad practice to have API keys, this is a read-only API key
# so that we do not get rate limited by Etherscan (and it's free to generate as
# many as you want)
env:
ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }}
ETHERSCAN_API_KEY: 76XKCZ4QKZYTJS8PBFUDZ292JBKEKS4974

jobs:
tests:
Expand Down
1 change: 1 addition & 0 deletions ethers-contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ethers-signers = { version = "0.1.3", path = "../ethers-signers" }
ethers-core = { version = "0.1.3", path = "../ethers-core" }

serde = { version = "1.0.110", default-features = false }
serde_json = "1.0.55"
rustc-hex = { version = "2.1.0", default-features = false }
thiserror = { version = "1.0.15", default-features = false }
once_cell = { version = "1.3.1", default-features = false }
Expand Down
69 changes: 57 additions & 12 deletions ethers-contract/ethers-contract-abigen/src/contract/methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,7 @@ fn expand_function(function: &Function, alias: Option<Ident>) -> Result<TokenStr

let outputs = expand_fn_outputs(&function.outputs)?;

let is_mutable = matches!(
function.state_mutability,
StateMutability::Nonpayable | StateMutability::Payable
);
let result = if !is_mutable {
quote! { ContractCall<P, S, #outputs> }
} else {
quote! { ContractCall<P, S, H256> }
};
let result = quote! { ContractCall<P, S, #outputs> };

let arg = expand_inputs_call_arg(&function.inputs);
let doc = util::expand_doc(&format!(
Expand Down Expand Up @@ -85,8 +77,13 @@ pub(crate) fn expand_inputs_call_arg(inputs: &[Param]) -> TokenStream {
let names = inputs
.iter()
.enumerate()
.map(|(i, param)| util::expand_input_name(i, &param.name));
quote! { ( #( #names ,)* ) }
.map(|(i, param)| util::expand_input_name(i, &param.name))
.collect::<Vec<TokenStream>>();
match names.len() {
0 => quote! { () },
1 => quote! { #( #names )* },
_ => quote! { ( #(#names, )* ) },
}
}

fn expand_fn_outputs(outputs: &[Param]) -> Result<TokenStream> {
Expand All @@ -113,6 +110,54 @@ mod tests {
use super::*;
use ethers_core::abi::ParamType;

#[test]
fn test_expand_inputs_call_arg() {
// no inputs
let params = vec![];
let token_stream = expand_inputs_call_arg(&params);
assert_eq!(token_stream.to_string(), "( )");

// single input
let params = vec![Param {
name: "arg_a".to_string(),
kind: ParamType::Address,
}];
let token_stream = expand_inputs_call_arg(&params);
assert_eq!(token_stream.to_string(), "arg_a");

// two inputs
let params = vec![
Param {
name: "arg_a".to_string(),
kind: ParamType::Address,
},
Param {
name: "arg_b".to_string(),
kind: ParamType::Uint(256usize),
},
];
let token_stream = expand_inputs_call_arg(&params);
assert_eq!(token_stream.to_string(), "( arg_a , arg_b , )");

// three inputs
let params = vec![
Param {
name: "arg_a".to_string(),
kind: ParamType::Address,
},
Param {
name: "arg_b".to_string(),
kind: ParamType::Uint(128usize),
},
Param {
name: "arg_c".to_string(),
kind: ParamType::Bool,
},
];
let token_stream = expand_inputs_call_arg(&params);
assert_eq!(token_stream.to_string(), "( arg_a , arg_b , arg_c , )");
}

#[test]
fn expand_inputs_empty() {
assert_quote!(expand_inputs(&[]).unwrap().to_string(), {},);
Expand Down Expand Up @@ -157,7 +202,7 @@ mod tests {
}

#[test]
fn expand_fn_outputs_muliple() {
fn expand_fn_outputs_multiple() {
assert_quote!(
expand_fn_outputs(&[
Param {
Expand Down
3 changes: 3 additions & 0 deletions ethers-contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ pub use factory::ContractFactory;

mod event;

mod multicall;
pub use multicall::Multicall;

/// This module exposes low lever builder structures which are only consumed by the
/// type-safe ABI bindings generators.
pub mod builders {
Expand Down
Loading

0 comments on commit a9bb98b

Please sign in to comment.