1use crate::{
2 Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, DatabaseExt, Result, Vm::*,
3 json::json_value_to_token,
4};
5use alloy_dyn_abi::DynSolValue;
6use alloy_evm::EvmEnv;
7use alloy_network::AnyNetwork;
8use alloy_primitives::{Address, B256, U256, map::AddressHashMap};
9use alloy_provider::Provider;
10use alloy_rpc_types::Filter;
11use alloy_sol_types::SolValue;
12use foundry_common::provider::ProviderBuilder;
13use foundry_evm_core::{
14 FoundryContextExt,
15 backend::{ContextUpdateFor, ForkAccountField, JournaledState, LocalForkId},
16 evm::{BlockEnvFor, EvmFactoryFor, FoundryContextFor, FoundryEvmNetwork, SpecFor, TxEnvFor},
17 fork::CreateFork,
18};
19use revm::context::ContextTr;
20
21impl Cheatcode for activeForkCall {
22 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
23 let Self {} = self;
24 ccx.ecx
25 .db()
26 .active_fork_id()
27 .map(|id| id.abi_encode())
28 .ok_or_else(|| fmt_err!("no active fork"))
29 }
30}
31
32impl Cheatcode for createFork_0Call {
33 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
34 let Self { urlOrAlias } = self;
35 create_fork(ccx, urlOrAlias, None)
36 }
37}
38
39impl Cheatcode for createFork_1Call {
40 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
41 let Self { urlOrAlias, blockNumber } = self;
42 create_fork(ccx, urlOrAlias, Some(blockNumber.saturating_to()))
43 }
44}
45
46impl Cheatcode for createFork_2Call {
47 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
48 let Self { urlOrAlias, txHash } = self;
49 create_fork_at_transaction(ccx, urlOrAlias, txHash)
50 }
51}
52
53impl Cheatcode for createSelectFork_0Call {
54 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
55 let Self { urlOrAlias } = self;
56 create_select_fork(ccx, urlOrAlias, None)
57 }
58}
59
60impl Cheatcode for createSelectFork_1Call {
61 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
62 let Self { urlOrAlias, blockNumber } = self;
63 create_select_fork(ccx, urlOrAlias, Some(blockNumber.saturating_to()))
64 }
65}
66
67impl Cheatcode for createSelectFork_2Call {
68 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
69 let Self { urlOrAlias, txHash } = self;
70 create_select_fork_at_transaction(ccx, urlOrAlias, txHash)
71 }
72}
73
74impl Cheatcode for rollFork_0Call {
75 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
76 let Self { blockNumber } = self;
77 persist_caller(ccx);
78 let result = fork_env_op::<FEN, _>(ccx.ecx, |db, evm_env, tx_env, inner| {
79 db.roll_fork(None, (*blockNumber).to(), evm_env, tx_env, inner)
80 .map(|context| ((), context))
81 })?;
82 record_fork_roll(ccx, None);
83 Ok(result)
84 }
85}
86
87impl Cheatcode for rollFork_1Call {
88 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
89 let Self { txHash } = self;
90 persist_caller(ccx);
91 let result = fork_env_op::<FEN, _>(ccx.ecx, |db, evm_env, tx_env, inner| {
92 db.roll_fork_to_transaction(None, *txHash, evm_env, tx_env, inner)
93 .map(|context| ((), context))
94 })?;
95 record_fork_roll(ccx, None);
96 Ok(result)
97 }
98}
99
100impl Cheatcode for rollFork_2Call {
101 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
102 let Self { forkId, blockNumber } = self;
103 persist_caller(ccx);
104 let result = fork_env_op::<FEN, _>(ccx.ecx, |db, evm_env, tx_env, inner| {
105 db.roll_fork(Some(*forkId), (*blockNumber).to(), evm_env, tx_env, inner)
106 .map(|context| ((), context))
107 })?;
108 record_fork_roll(ccx, Some(*forkId));
109 Ok(result)
110 }
111}
112
113impl Cheatcode for rollFork_3Call {
114 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
115 let Self { forkId, txHash } = self;
116 persist_caller(ccx);
117 let result = fork_env_op::<FEN, _>(ccx.ecx, |db, evm_env, tx_env, inner| {
118 db.roll_fork_to_transaction(Some(*forkId), *txHash, evm_env, tx_env, inner)
119 .map(|context| ((), context))
120 })?;
121 record_fork_roll(ccx, Some(*forkId));
122 Ok(result)
123 }
124}
125
126impl Cheatcode for selectForkCall {
127 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
128 let Self { forkId } = self;
129 persist_caller(ccx);
130 check_broadcast(ccx.state)?;
131 let source_fork_id = ccx.ecx.db().active_fork_id();
132 let initial = ccx.state.created_account_bindings(None);
133 let propagated = persistent_created_accounts(ccx);
134 let result = fork_env_op::<FEN, _>(ccx.ecx, |db, evm_env, tx_env, inner| {
135 db.select_fork(*forkId, evm_env, tx_env, inner).map(|context| ((), context))
136 })?;
137 record_fork_switch(ccx, source_fork_id, initial, propagated);
138 Ok(result)
139 }
140}
141
142impl Cheatcode for transact_0Call {
143 fn apply_full<FEN: FoundryEvmNetwork>(
144 &self,
145 ccx: &mut CheatsCtxt<'_, '_, FEN>,
146 executor: &mut dyn CheatcodesExecutor<FEN>,
147 ) -> Result {
148 let Self { txHash } = *self;
149 transact(ccx, executor, txHash, None)
150 }
151}
152
153impl Cheatcode for transact_1Call {
154 fn apply_full<FEN: FoundryEvmNetwork>(
155 &self,
156 ccx: &mut CheatsCtxt<'_, '_, FEN>,
157 executor: &mut dyn CheatcodesExecutor<FEN>,
158 ) -> Result {
159 let Self { forkId, txHash } = *self;
160 transact(ccx, executor, txHash, Some(forkId))
161 }
162}
163
164impl Cheatcode for allowCheatcodesCall {
165 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
166 let Self { account } = self;
167 ccx.ecx.db_mut().allow_cheatcode_access(*account);
168 Ok(Default::default())
169 }
170}
171
172impl Cheatcode for makePersistent_0Call {
173 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
174 let Self { account } = self;
175 ccx.ecx.db_mut().add_persistent_account(*account);
176 Ok(Default::default())
177 }
178}
179
180impl Cheatcode for makePersistent_1Call {
181 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
182 let Self { account0, account1 } = self;
183 ccx.ecx.db_mut().add_persistent_account(*account0);
184 ccx.ecx.db_mut().add_persistent_account(*account1);
185 Ok(Default::default())
186 }
187}
188
189impl Cheatcode for makePersistent_2Call {
190 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
191 let Self { account0, account1, account2 } = self;
192 ccx.ecx.db_mut().add_persistent_account(*account0);
193 ccx.ecx.db_mut().add_persistent_account(*account1);
194 ccx.ecx.db_mut().add_persistent_account(*account2);
195 Ok(Default::default())
196 }
197}
198
199impl Cheatcode for makePersistent_3Call {
200 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
201 let Self { accounts } = self;
202 for account in accounts {
203 ccx.ecx.db_mut().add_persistent_account(*account);
204 }
205 Ok(Default::default())
206 }
207}
208
209impl Cheatcode for revokePersistent_0Call {
210 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
211 let Self { account } = self;
212 ccx.ecx.db_mut().remove_persistent_account(account);
213 Ok(Default::default())
214 }
215}
216
217impl Cheatcode for revokePersistent_1Call {
218 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
219 let Self { accounts } = self;
220 for account in accounts {
221 ccx.ecx.db_mut().remove_persistent_account(account);
222 }
223 Ok(Default::default())
224 }
225}
226
227impl Cheatcode for isPersistentCall {
228 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
229 let Self { account } = self;
230 Ok(ccx.ecx.db().is_persistent(account).abi_encode())
231 }
232}
233
234impl Cheatcode for rpc_0Call {
235 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
236 let Self { method, params } = self;
237 let url =
238 ccx.ecx.db().active_fork_url().ok_or_else(|| fmt_err!("no active fork URL found"))?;
239 let result = rpc_call(&url, method, params)?;
240 refresh_active_fork_state(ccx, method, params)?;
241 Ok(result)
242 }
243}
244
245impl Cheatcode for rpc_1Call {
246 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
247 let Self { urlOrAlias, method, params } = self;
248 let url = state.config.rpc_endpoint(urlOrAlias)?.url()?;
249 rpc_call(&url, method, params)
250 }
251}
252
253impl Cheatcode for rpcJson_0Call {
254 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
255 let Self { method, params } = self;
256 let url =
257 ccx.ecx.db().active_fork_url().ok_or_else(|| fmt_err!("no active fork URL found"))?;
258 let result = rpc_json_call(&url, method, params)?;
259 refresh_active_fork_state(ccx, method, params)?;
260 Ok(result)
261 }
262}
263
264impl Cheatcode for rpcJson_1Call {
265 fn apply<FEN: FoundryEvmNetwork>(&self, state: &mut Cheatcodes<FEN>) -> Result {
266 let Self { urlOrAlias, method, params } = self;
267 let url = state.config.rpc_endpoint(urlOrAlias)?.url()?;
268 rpc_json_call(&url, method, params)
269 }
270}
271
272impl Cheatcode for eth_getLogsCall {
273 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
274 let Self { fromBlock, toBlock, target, topics } = self;
275 let (Ok(from_block), Ok(to_block)) = (u64::try_from(fromBlock), u64::try_from(toBlock))
276 else {
277 bail!("blocks in block range must be less than 2^64")
278 };
279
280 if topics.len() > 4 {
281 bail!("topics array must contain at most 4 elements")
282 }
283
284 let url =
285 ccx.ecx.db().active_fork_url().ok_or_else(|| fmt_err!("no active fork URL found"))?;
286 let provider = ProviderBuilder::<AnyNetwork>::new(&url).build()?;
287 let mut filter = Filter::new().address(*target).from_block(from_block).to_block(to_block);
288 for (i, &topic) in topics.iter().enumerate() {
289 filter.topics[i] = topic.into();
290 }
291
292 let logs = foundry_common::block_on(provider.get_logs(&filter))
293 .map_err(|e| fmt_err!("failed to get logs: {e}"))?;
294
295 let eth_logs = logs
296 .into_iter()
297 .map(|log| EthGetLogs {
298 emitter: log.address(),
299 topics: log.topics().to_vec(),
300 data: log.inner.data.data,
301 blockHash: log.block_hash.unwrap_or_default(),
302 blockNumber: log.block_number.unwrap_or_default(),
303 transactionHash: log.transaction_hash.unwrap_or_default(),
304 transactionIndex: log.transaction_index.unwrap_or_default(),
305 logIndex: U256::from(log.log_index.unwrap_or_default()),
306 removed: log.removed,
307 })
308 .collect::<Vec<_>>();
309
310 Ok(eth_logs.abi_encode())
311 }
312}
313
314impl Cheatcode for getRawBlockHeaderCall {
315 fn apply_stateful<FEN: FoundryEvmNetwork>(&self, ccx: &mut CheatsCtxt<'_, '_, FEN>) -> Result {
316 let Self { blockNumber } = self;
317 let url = ccx.ecx.db().active_fork_url().ok_or_else(|| fmt_err!("no active fork"))?;
318 let provider = ProviderBuilder::<AnyNetwork>::new(&url).build()?;
319 let block_number = u64::try_from(blockNumber)
320 .map_err(|_| fmt_err!("block number must be less than 2^64"))?;
321 let block =
322 foundry_common::block_on(async move { provider.get_block(block_number.into()).await })
323 .map_err(|e| fmt_err!("failed to get block: {e}"))?
324 .ok_or_else(|| fmt_err!("block {block_number} not found"))?;
325
326 let header: alloy_consensus::Header = block
327 .into_inner()
328 .header
329 .inner
330 .try_into_header()
331 .map_err(|e| fmt_err!("failed to convert to header: {e}"))?;
332 Ok(alloy_rlp::encode(&header).abi_encode())
333 }
334}
335
336fn create_select_fork<FEN: FoundryEvmNetwork>(
338 ccx: &mut CheatsCtxt<'_, '_, FEN>,
339 url_or_alias: &str,
340 block: Option<u64>,
341) -> Result {
342 check_broadcast(ccx.state)?;
343
344 let fork = create_fork_request(ccx, url_or_alias, block)?;
345 let source_fork_id = ccx.ecx.db().active_fork_id();
346 let initial = ccx.state.created_account_bindings(None);
347 let propagated = persistent_created_accounts(ccx);
348 let result = fork_env_op::<FEN, _>(ccx.ecx, |db, evm_env, tx_env, inner| {
349 db.create_select_fork(fork, evm_env, tx_env, inner)
350 })?;
351 record_fork_switch(ccx, source_fork_id, initial, propagated);
352 Ok(result)
353}
354
355fn create_fork<FEN: FoundryEvmNetwork>(
357 ccx: &mut CheatsCtxt<'_, '_, FEN>,
358 url_or_alias: &str,
359 block: Option<u64>,
360) -> Result {
361 let fork = create_fork_request(ccx, url_or_alias, block)?;
362 let id = ccx.ecx.db_mut().create_fork(fork)?;
363 Ok(id.abi_encode())
364}
365
366fn create_select_fork_at_transaction<FEN: FoundryEvmNetwork>(
368 ccx: &mut CheatsCtxt<'_, '_, FEN>,
369 url_or_alias: &str,
370 transaction: &B256,
371) -> Result {
372 check_broadcast(ccx.state)?;
373
374 let fork = create_fork_request(ccx, url_or_alias, None)?;
375 let source_fork_id = ccx.ecx.db().active_fork_id();
376 let initial = ccx.state.created_account_bindings(None);
377 let propagated = persistent_created_accounts(ccx);
378 let result = fork_env_op::<FEN, _>(ccx.ecx, |db, evm_env, tx_env, inner| {
379 db.create_select_fork_at_transaction(fork, evm_env, tx_env, inner, *transaction)
380 })?;
381 record_fork_switch(ccx, source_fork_id, initial, propagated);
382 Ok(result)
383}
384
385fn create_fork_at_transaction<FEN: FoundryEvmNetwork>(
387 ccx: &mut CheatsCtxt<'_, '_, FEN>,
388 url_or_alias: &str,
389 transaction: &B256,
390) -> Result {
391 let fork = create_fork_request(ccx, url_or_alias, None)?;
392 let id = ccx.ecx.db_mut().create_fork_at_transaction(fork, *transaction)?;
393 Ok(id.abi_encode())
394}
395
396fn create_fork_request<FEN: FoundryEvmNetwork>(
398 ccx: &mut CheatsCtxt<'_, '_, FEN>,
399 url_or_alias: &str,
400 block: Option<u64>,
401) -> Result<CreateFork> {
402 persist_caller(ccx);
403
404 let rpc_endpoint = ccx.state.config.rpc_endpoint(url_or_alias)?;
405 let url = rpc_endpoint.url()?;
406 let mut evm_opts = ccx.state.config.evm_opts.clone();
407 evm_opts.fork_block_number = block;
408 evm_opts.fork_block_number_is_inferred = false;
409 evm_opts.fork_retries = rpc_endpoint.config.retries;
410 evm_opts.fork_retry_backoff = rpc_endpoint.config.retry_backoff;
411 if let Some(Ok(auth)) = rpc_endpoint.auth {
412 evm_opts.fork_headers = Some(vec![format!("Authorization: {auth}")]);
413 }
414 let fork = CreateFork {
415 enable_caching: !ccx.state.config.no_storage_caching
416 && ccx.state.config.rpc_storage_caching.enable_for_endpoint(&url),
417 url,
418 evm_opts,
419 resolved: None,
420 };
421 Ok(fork)
422}
423
424#[cfg(feature = "monad")]
426fn apply_context_update<FEN: FoundryEvmNetwork>(
427 ecx: &mut FoundryContextFor<'_, FEN>,
428 context_update: foundry_evm_core::backend::ContextUpdate<foundry_evm_core::evm::ChainFor<FEN>>,
429) {
430 match context_update {
431 foundry_evm_core::backend::ContextUpdate::Unchanged => {}
432 foundry_evm_core::backend::ContextUpdate::Replace(chain_context) => {
433 *ecx.chain_mut() = chain_context;
434 foundry_evm_core::refresh_chain_journal(ecx);
435 }
436 foundry_evm_core::backend::ContextUpdate::Rebase => {
437 foundry_evm_core::refresh_chain_journal(ecx);
438 }
439 }
440}
441
442fn fork_env_op<FEN: FoundryEvmNetwork, T: SolValue>(
446 ecx: &mut FoundryContextFor<'_, FEN>,
447 f: impl FnOnce(
448 &mut <FoundryContextFor<'_, FEN> as ContextTr>::Db,
449 &mut EvmEnv<SpecFor<FEN>, BlockEnvFor<FEN>>,
450 &mut TxEnvFor<FEN>,
451 &mut JournaledState,
452 ) -> eyre::Result<(T, ContextUpdateFor<EvmFactoryFor<FEN>>)>,
453) -> Result {
454 let mut evm_env = ecx.evm_clone();
455 let mut tx_env = ecx.tx_clone();
456 let (db, inner) = ecx.db_journal_inner_mut();
457 let (result, context_update) = f(db, &mut evm_env, &mut tx_env, inner)?;
458 ecx.set_evm(evm_env);
459 ecx.set_tx(tx_env);
460 #[cfg(not(feature = "monad"))]
461 let _ = context_update;
462 #[cfg(feature = "monad")]
463 apply_context_update::<FEN>(ecx, context_update);
464 Ok(result.abi_encode())
465}
466
467fn persistent_created_accounts<FEN: FoundryEvmNetwork>(
468 ccx: &CheatsCtxt<'_, '_, FEN>,
469) -> Vec<(Address, usize)> {
470 let fork_id = ccx.ecx.db().active_fork_id();
471 ccx.state
472 .created_account_bindings(fork_id)
473 .into_iter()
474 .filter(|(address, _)| ccx.ecx.db().is_persistent(address))
475 .collect()
476}
477
478fn record_fork_switch<FEN: FoundryEvmNetwork>(
479 ccx: &mut CheatsCtxt<'_, '_, FEN>,
480 source_fork_id: Option<LocalForkId>,
481 initial: AddressHashMap<usize>,
482 propagated: Vec<(Address, usize)>,
483) {
484 let target_fork_id = ccx.ecx.db().active_fork_id();
485 ccx.state.fork_block_number_override = ccx.ecx.db().active_fork_block_number();
486 if source_fork_id != target_fork_id {
487 ccx.state.commit_created_account_changes(source_fork_id);
488 }
489 ccx.state.record_initial_created_accounts(target_fork_id, initial);
490 ccx.state.record_propagated_accounts(target_fork_id, propagated);
491}
492
493fn record_fork_roll<FEN: FoundryEvmNetwork>(
494 ccx: &mut CheatsCtxt<'_, '_, FEN>,
495 target_fork_id: Option<LocalForkId>,
496) {
497 let active_fork_id = ccx.ecx.db().active_fork_id();
498 if target_fork_id.is_none() || target_fork_id == active_fork_id {
499 ccx.state.fork_block_number_override = ccx.ecx.db().active_fork_block_number();
500 ccx.state.commit_created_account_changes(active_fork_id);
501 }
502}
503
504fn check_broadcast<FEN: FoundryEvmNetwork>(state: &Cheatcodes<FEN>) -> Result<()> {
505 if state.broadcast.is_none() {
506 Ok(())
507 } else {
508 Err(fmt_err!("cannot select forks during a broadcast"))
509 }
510}
511
512fn transact<FEN: FoundryEvmNetwork>(
513 ccx: &mut CheatsCtxt<'_, '_, FEN>,
514 executor: &mut dyn CheatcodesExecutor<FEN>,
515 transaction: B256,
516 fork_id: Option<U256>,
517) -> Result {
518 let context_update = executor.transact_on_db(ccx.state, ccx.ecx, fork_id, transaction)?;
519 #[cfg(not(feature = "monad"))]
520 let _ = context_update;
521 #[cfg(feature = "monad")]
522 apply_context_update::<FEN>(ccx.ecx, context_update);
523 Ok(Default::default())
524}
525
526fn persist_caller<FEN: FoundryEvmNetwork>(ccx: &mut CheatsCtxt<'_, '_, FEN>) {
531 ccx.ecx.db_mut().add_persistent_account(ccx.caller);
532}
533
534fn rpc_call(url: &str, method: &str, params: &str) -> Result {
536 let result = rpc_result(url, method, params)?;
537 let result_as_tokens = convert_to_bytes(
538 &json_value_to_token(&result, None)
539 .map_err(|err| fmt_err!("failed to parse result: {err}"))?,
540 );
541
542 let payload = match &result_as_tokens {
543 DynSolValue::Bytes(b) => b.clone(),
544 _ => result_as_tokens.abi_encode(),
545 };
546 Ok(DynSolValue::Bytes(payload).abi_encode())
547}
548
549fn rpc_json_call(url: &str, method: &str, params: &str) -> Result {
551 let result = rpc_result(url, method, params)?;
552 Ok(serde_json::to_string(&result)?.abi_encode())
553}
554
555fn refresh_active_fork_state<FEN: FoundryEvmNetwork>(
559 ccx: &mut CheatsCtxt<'_, '_, FEN>,
560 method: &str,
561 params: &str,
562) -> Result<()> {
563 let account_field = match method {
564 "anvil_setBalance"
565 | "hardhat_setBalance"
566 | "tenderly_setBalance"
567 | "anvil_addBalance"
568 | "hardhat_addBalance"
569 | "tenderly_addBalance" => Some(ForkAccountField::Balance),
570 "anvil_setNonce" | "hardhat_setNonce" | "evm_setAccountNonce" => {
571 Some(ForkAccountField::Nonce)
572 }
573 "anvil_setCode" | "hardhat_setCode" => Some(ForkAccountField::Code),
574 "anvil_setStorageAt" | "hardhat_setStorageAt" => None,
575 _ => return Ok(()),
576 };
577
578 let Ok(params) = serde_json::from_str::<serde_json::Value>(params) else { return Ok(()) };
579 let Some(address) =
580 params.get(0).and_then(|v| v.as_str()).and_then(|s| s.parse::<Address>().ok())
581 else {
582 return Ok(());
583 };
584
585 let (db, journaled_state) = ccx.ecx.db_journal_inner_mut();
586 if let Some(field) = account_field {
587 db.refresh_fork_account(address, field, journaled_state)?;
588 } else {
589 let Some(slot) =
590 params.get(1).and_then(|v| v.as_str()).and_then(|s| s.parse::<U256>().ok())
591 else {
592 return Ok(());
593 };
594 db.refresh_fork_storage(address, slot, journaled_state)?;
595 }
596 Ok(())
597}
598
599fn rpc_result(url: &str, method: &str, params: &str) -> Result<serde_json::Value> {
600 let provider = ProviderBuilder::<AnyNetwork>::new(url).build()?;
601 let params_json: serde_json::Value = serde_json::from_str(params)?;
602 foundry_common::block_on(provider.raw_request(method.to_string().into(), params_json))
603 .map_err(|err| fmt_err!("{method:?}: {err}"))
604}
605
606fn convert_to_bytes(token: &DynSolValue) -> DynSolValue {
608 match token {
609 DynSolValue::FixedBytes(bytes, size) => {
612 DynSolValue::Bytes(bytes.as_slice()[..*size].to_vec())
613 }
614 DynSolValue::Address(addr) => DynSolValue::Bytes(addr.to_vec()),
615 val => val.clone(),
616 }
617}