Skip to content

Commit

Permalink
feat(cheatcodes): add rpc with url overload (#8316)
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes authored Jun 30, 2024
1 parent bd72b05 commit 9058812
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 39 deletions.
60 changes: 40 additions & 20 deletions crates/cheatcodes/assets/cheatcodes.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions crates/cheatcodes/spec/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,12 @@ interface Vm {
#[cheatcode(group = Evm, safety = Safe)]
function rpc(string calldata method, string calldata params) external returns (bytes memory data);

/// Performs an Ethereum JSON-RPC request to the given endpoint.
#[cheatcode(group = Evm, safety = Safe)]
function rpc(string calldata urlOrAlias, string calldata method, string calldata params)
external
returns (bytes memory data);

/// Gets all the logs according to specified filter.
#[cheatcode(group = Evm, safety = Safe)]
function eth_getLogs(uint256 fromBlock, uint256 toBlock, address target, bytes32[] memory topics)
Expand Down
50 changes: 32 additions & 18 deletions crates/cheatcodes/src/evm/fork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -233,29 +233,20 @@ impl Cheatcode for isPersistentCall {
}
}

impl Cheatcode for rpcCall {
impl Cheatcode for rpc_0Call {
fn apply_stateful<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { method, params } = self;
let url =
ccx.ecx.db.active_fork_url().ok_or_else(|| fmt_err!("no active fork URL found"))?;
let provider = ProviderBuilder::new(&url).build()?;
let params_json: serde_json::Value = serde_json::from_str(params)?;
let result =
foundry_common::block_on(provider.raw_request(method.clone().into(), params_json))
.map_err(|err| fmt_err!("{method:?}: {err}"))?;

let result_as_tokens = match crate::json::json_value_to_token(&result)
.map_err(|err| fmt_err!("failed to parse result: {err}"))?
{
DynSolValue::FixedBytes(bytes, size) => {
// converted fixed bytes to bytes to prevent evm encoding issues: <https://github.com/foundry-rs/foundry/issues/8287>
DynSolValue::Bytes(bytes.as_slice()[..size].to_vec())
}
DynSolValue::Address(addr) => DynSolValue::Bytes(addr.to_vec()),
val => val,
};
rpc_call(&url, method, params)
}
}

Ok(result_as_tokens.abi_encode())
impl Cheatcode for rpc_1Call {
fn apply(&self, state: &mut Cheatcodes) -> Result {
let Self { urlOrAlias, method, params } = self;
let url = state.config.rpc_url(urlOrAlias)?;
rpc_call(&url, method, params)
}
}

Expand Down Expand Up @@ -392,3 +383,26 @@ fn check_broadcast(state: &Cheatcodes) -> Result<()> {
fn persist_caller<DB: DatabaseExt>(ccx: &mut CheatsCtxt<DB>) {
ccx.ecx.db.add_persistent_account(ccx.caller);
}

/// Performs an Ethereum JSON-RPC request to the given endpoint.
fn rpc_call(url: &str, method: &str, params: &str) -> Result {
let provider = ProviderBuilder::new(url).build()?;
let params_json: serde_json::Value = serde_json::from_str(params)?;
let result =
foundry_common::block_on(provider.raw_request(method.to_string().into(), params_json))
.map_err(|err| fmt_err!("{method:?}: {err}"))?;

let result_as_tokens = match crate::json::json_value_to_token(&result)
.map_err(|err| fmt_err!("failed to parse result: {err}"))?
{
// Convert fixed bytes to bytes to prevent encoding issues.
// See: <https://github.com/foundry-rs/foundry/issues/8287>
DynSolValue::FixedBytes(bytes, size) => {
DynSolValue::Bytes(bytes.as_slice()[..size].to_vec())
}
DynSolValue::Address(addr) => DynSolValue::Bytes(addr.to_vec()),
val => val,
};

Ok(result_as_tokens.abi_encode())
}
3 changes: 2 additions & 1 deletion testdata/cheats/Vm.sol

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions testdata/default/cheats/Fork2.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,12 @@ contract ForkTest is DSTest {
bytes memory result = vm.rpc("eth_getBalance", file);
assertEq(hex"10b7c11bcb51e6", result);
}

function testRpcWithUrl() public {
bytes memory result = vm.rpc("rpcAlias", "eth_blockNumber", "[]");
uint256 decodedResult = vm.parseUint(vm.toString(result));
assertGt(decodedResult, 20_000_000);
}
}

contract DummyContract {
Expand Down

0 comments on commit 9058812

Please sign in to comment.