Skip to content

Commit

Permalink
Add call builder and eth_call state overrides (gakonst#1340)
Browse files Browse the repository at this point in the history
* Add call builder and eth_call state overrides

* Fix <Caller as Future>::poll impl

* Move call overrides to ethers_provider::call_raw

* Add example for call_raw overrides

* Add support for contract call overrides

* Documentation and convenience impls for call_raw types

* Test for eth_call state overrides

* ci: install geth

Co-authored-by: Georgios Konstantopoulos <[email protected]>
  • Loading branch information
gio256 and gakonst authored Jun 4, 2022
1 parent 3b54f18 commit a532eb4
Show file tree
Hide file tree
Showing 7 changed files with 801 additions and 5 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,16 @@ jobs:
- name: Checkout sources
uses: actions/checkout@v2

- name: Install geth (for state overrides example)
run: |
mkdir -p "$HOME/bin"
wget -q https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.9.23-8c2f2715.tar.gz
tar -xvf geth-linux-amd64-1.9.23-8c2f2715.tar.gz
mv geth-linux-amd64-1.9.23-8c2f2715/geth $HOME/bin/geth
chmod u+x "$HOME/bin/geth"
export PATH=$HOME/bin:$PATH
geth version
- name: Install Anvil
uses: foundry-rs/foundry-toolchain@v1
with:
Expand Down
38 changes: 36 additions & 2 deletions ethers-contract/src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ use ethers_core::{
},
utils::id,
};
use ethers_providers::{Middleware, PendingTransaction, ProviderError};
use ethers_providers::{
call_raw::{CallBuilder, RawCall},
Middleware, PendingTransaction, ProviderError,
};

use std::{borrow::Cow, fmt::Debug, marker::PhantomData, sync::Arc};
use std::{borrow::Cow, fmt::Debug, future::Future, marker::PhantomData, sync::Arc};

use thiserror::Error as ThisError;

Expand Down Expand Up @@ -169,6 +172,37 @@ where
Ok(data)
}

/// Returns an implementer of [`RawCall`] which can be `.await`d to query the blockchain via
/// `eth_call`, returning the deoded return data.
///
/// The returned call can also be used to override the input parameters to `eth_call`.
///
/// Note: this function _does not_ send a transaction from your account
pub fn call_raw(
&self,
) -> impl RawCall<'_> + Future<Output = Result<D, ContractError<M>>> + Debug {
let call = self.call_raw_bytes();
call.map(move |res: Result<Bytes, ProviderError>| {
let bytes = res.map_err(ContractError::ProviderError)?;
decode_function_data(&self.function, &bytes, false).map_err(From::from)
})
}

/// Returns a [`CallBuilder`] which can be `.await`d to query the blochcain via `eth_call`,
/// returning the raw bytes from the transaction.
///
/// The returned call can also be used to override the input parameters to `eth_call`.
///
/// Note: this function _does not_ send a transaction from your account
pub fn call_raw_bytes(&self) -> CallBuilder<'_, M::Provider> {
let call = self.client.provider().call_raw(&self.tx);
if let Some(block) = self.block {
call.block(block)
} else {
call
}
}

/// Signs and broadcasts the provided transaction
pub async fn send(&self) -> Result<PendingTransaction<'_, M::Provider>, ContractError<M>> {
self.client
Expand Down
26 changes: 23 additions & 3 deletions ethers-contract/src/factory.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::{Contract, ContractError};
use std::marker::PhantomData;

use ethers_core::{
abi::{Abi, Token, Tokenize},
Expand All @@ -8,12 +7,15 @@ use ethers_core::{
TransactionReceipt, TransactionRequest, U256, U64,
},
};
use ethers_providers::Middleware;
use ethers_providers::{
call_raw::{CallBuilder, RawCall},
Middleware,
};

#[cfg(not(feature = "legacy"))]
use ethers_core::types::Eip1559TransactionRequest;

use std::sync::Arc;
use std::{marker::PhantomData, sync::Arc};

/// Helper which manages the deployment transaction of a smart contract.
///
Expand Down Expand Up @@ -114,6 +116,15 @@ impl<M: Middleware, C: From<Contract<M>>> ContractDeployer<M, C> {
self.deployer.call().await
}

/// Returns a CallBuilder, which when awaited executes the deployment of this contract via
/// `eth_call`. This call resolves to the returned data which would have been stored at the
/// destination address had the deploy transaction been executed via `send()`.
///
/// Note: this function _does not_ send a transaction from your account
pub fn call_raw(&self) -> CallBuilder<'_, M::Provider> {
self.deployer.call_raw()
}

/// Broadcasts the contract deployment transaction and after waiting for it to
/// be sufficiently confirmed (default: 1), it returns a new instance of the contract type at
/// the deployed contract's address.
Expand Down Expand Up @@ -203,6 +214,15 @@ impl<M: Middleware> Deployer<M> {
Ok(())
}

/// Returns a CallBuilder, which when awaited executes the deployment of this contract via
/// `eth_call`. This call resolves to the returned data which would have been stored at the
/// destination address had the deploy transaction been executed via `send()`.
///
/// Note: this function _does not_ send a transaction from your account
pub fn call_raw(&self) -> CallBuilder<'_, M::Provider> {
self.client.provider().call_raw(&self.tx).block(self.block.into())
}

/// Broadcasts the contract deployment transaction and after waiting for it to
/// be sufficiently confirmed (default: 1), it returns a [`Contract`](crate::Contract)
/// struct at the deployed contract's address.
Expand Down
Loading

0 comments on commit a532eb4

Please sign in to comment.