diff --git a/src/client/client.rs b/src/client/client.rs index 4befbaa..0252b08 100644 --- a/src/client/client.rs +++ b/src/client/client.rs @@ -42,6 +42,12 @@ impl Client { evm.call(to, calldata, value) } + pub async fn estimate_gas(&self, to: &Address, calldata: &Vec, value: U256) -> Result { + let payload = self.consensus.get_execution_payload().await?; + let mut evm = Evm::new(self.execution.clone(), payload); + evm.estimate_gas(to, calldata, value) + } + pub async fn get_balance(&self, address: &Address) -> Result { let payload = self.consensus.get_execution_payload().await?; let account = self.execution.get_account(&address, None, &payload).await?; diff --git a/src/client/rpc.rs b/src/client/rpc.rs index c2058ed..8d9142c 100644 --- a/src/client/rpc.rs +++ b/src/client/rpc.rs @@ -49,6 +49,8 @@ trait EthRpc { async fn get_code(&self, address: &str, block: &str) -> Result; #[method(name = "call")] async fn call(&self, opts: CallOpts, block: &str) -> Result; + #[method(name = "estimateGas")] + async fn estimate_gas(&self, opts: CallOpts) -> Result; #[method(name = "chainId")] fn chain_id(&self) -> Result; } @@ -112,6 +114,18 @@ impl EthRpcServer for RpcInner { } } + async fn estimate_gas(&self, opts: CallOpts) -> Result { + let to = convert_err(Address::from_str(&opts.to))?; + let data = convert_err(hex_str_to_bytes(&opts.data.unwrap_or("0x".to_string())))?; + let value = convert_err(U256::from_str_radix( + &opts.value.unwrap_or("0x0".to_string()), + 16, + ))?; + + let gas = convert_err(self.client.estimate_gas(&to, &data, value).await)?; + Ok(u64_to_hex_string(gas)) + } + fn chain_id(&self) -> Result { let id = self.client.chain_id(); Ok(u64_to_hex_string(id)) diff --git a/src/execution/evm.rs b/src/execution/evm.rs index 0d26f80..0769d74 100644 --- a/src/execution/evm.rs +++ b/src/execution/evm.rs @@ -44,6 +44,25 @@ impl Evm { TransactOut::Call(bytes) => Ok(bytes.to_vec()), } } + + pub fn estimate_gas(&mut self, to: &Address, calldata: &Vec, value: U256) -> Result { + let mut env = Env::default(); + let mut tx = revm::TxEnv::default(); + tx.transact_to = TransactTo::Call(*to); + tx.data = Bytes::from(calldata.clone()); + tx.value = value; + env.tx = tx; + + self.evm.env = env; + + let gas = self.evm.transact().2; + + if let Some(err) = &self.evm.db.as_ref().unwrap().error { + return Err(eyre::eyre!(err.clone())); + } + + Ok(gas) + } } struct ProofDB {