Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion ethcontract/src/contract/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
//! intended to be used directly but to be used by a contract `Instance` with
//! [Instance::method](ethcontract::contract::Instance::method).

use crate::state_overrides::StateOverrides;
use crate::transaction::{Account, GasPrice, TransactionBuilder, TransactionResult};
use crate::{batch::CallBatch, errors::MethodError, tokens::Tokenize};
use ethcontract_common::abi::{Function, Token};
use std::marker::PhantomData;
use web3::types::{AccessList, Address, BlockId, Bytes, CallRequest, U256};
use web3::helpers::CallFuture;
use web3::types::{AccessList, Address, BlockId, BlockNumber, Bytes, CallRequest, U256};
use web3::Transport;
use web3::{api::Web3, BatchTransport};

Expand Down Expand Up @@ -152,6 +154,14 @@ impl<T: Transport, R: Tokenize> MethodBuilder<T, R> {
pub async fn call(self) -> Result<R, MethodError> {
self.view().call().await
}

/// Same as [`call`] but allows to also specify state overrides with the call.
pub async fn call_with_state_overrides(
self,
overrides: &StateOverrides,
) -> Result<R, MethodError> {
self.view().call_with_state_overrides(overrides).await
}
}

/// Data used for building a contract method call. The view method builder can't
Expand Down Expand Up @@ -243,6 +253,20 @@ impl<T: Transport, R: Tokenize> ViewMethodBuilder<T, R> {
convert_response::<_, R>(future, function).await
}

/// Same as [`call`] but also allows to specify state overrides for the call.
pub async fn call_with_state_overrides(
self,
overrides: &StateOverrides,
) -> Result<R, MethodError> {
let transport = &self.m.web3.transport().clone();
let (function, call, block) = self.decompose();
let req = web3::helpers::serialize(&call);
let block = web3::helpers::serialize(&block.unwrap_or_else(|| BlockNumber::Latest.into()));
let overrides = web3::helpers::serialize(overrides);
let future = CallFuture::new(transport.execute("eth_call", vec![req, block, overrides]));
convert_response::<_, R>(future, function).await
}

/// Adds this view method to a batch. Allows execution with other contract calls in one roundtrip
/// The returned future only resolve once `batch` is resolved. Panics, if `batch` is dropped before
/// executing
Expand Down
1 change: 1 addition & 0 deletions ethcontract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ pub mod errors;
mod int;
pub mod log;
pub mod secret;
pub mod state_overrides;
pub mod tokens;
pub mod transaction;
pub mod transport;
Expand Down
37 changes: 37 additions & 0 deletions ethcontract/src/state_overrides.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Contains data structures needed to specify
//! state overrides for `eth_call`s.

use primitive_types::{H160, H256, U256};
use serde::Serialize;
use std::collections::HashMap;
use web3::types::{Bytes, U64};

/// State overrides.
pub type StateOverrides = HashMap<H160, StateOverride>;

/// State override object.
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct StateOverride {
/// Fake balance to set for the account before executing the call.
#[serde(skip_serializing_if = "Option::is_none")]
pub balance: Option<U256>,

/// Fake nonce to set for the account before executing the call.
#[serde(skip_serializing_if = "Option::is_none")]
pub nonce: Option<U64>,

/// Fake EVM bytecode to inject into the account before executing the call.
#[serde(skip_serializing_if = "Option::is_none")]
pub code: Option<Bytes>,

/// Fake key-value mapping to override **all** slots in the account storage
/// before executing the call.
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<HashMap<H256, H256>>,

/// Fake key-value mapping to override **individual** slots in the account
/// storage before executing the call.
#[serde(skip_serializing_if = "Option::is_none")]
pub state_diff: Option<HashMap<H256, H256>>,
}
Loading