Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 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
40 changes: 40 additions & 0 deletions crates/cheatcodes/assets/cheatcodes.json

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

12 changes: 12 additions & 0 deletions crates/cheatcodes/spec/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,18 @@ interface Vm {
#[cheatcode(group = Filesystem)]
function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode);

/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath) external returns (address deployedAddress);

/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
///
/// Additionaly accepts abi-encoded constructor arguments.
#[cheatcode(group = Filesystem)]
function deployCode(string calldata artifactPath, bytes calldata constructorArgs) external returns (address deployedAddress);

/// Gets the deployed bytecode from an artifact file. Takes in the relative path to the json file or the path to the
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
#[cheatcode(group = Filesystem)]
Expand Down
24 changes: 18 additions & 6 deletions crates/cheatcodes/src/evm/fork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,28 +127,36 @@ impl Cheatcode for selectForkCall {
}

impl Cheatcode for transact_0Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_full_with_executor<DB: DatabaseExt, E: crate::CheatcodesExecutor>(
&self,
ccx: &mut CheatsCtxt<DB>,
executor: &mut E,
) -> Result {
let Self { txHash } = *self;
ccx.ecx.db.transact(
None,
txHash,
&mut ccx.ecx.env,
&mut ccx.ecx.journaled_state,
ccx.state,
&mut executor.get_inspector(ccx.state),
)?;
Ok(Default::default())
}
}

impl Cheatcode for transact_1Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
fn apply_full_with_executor<DB: DatabaseExt, E: crate::CheatcodesExecutor>(
&self,
ccx: &mut CheatsCtxt<DB>,
executor: &mut E,
) -> Result {
let Self { forkId, txHash } = *self;
ccx.ecx.db.transact(
Some(forkId),
txHash,
&mut ccx.ecx.env,
&mut ccx.ecx.journaled_state,
ccx.state,
&mut executor.get_inspector(ccx.state),
)?;
Ok(Default::default())
}
Expand Down Expand Up @@ -192,7 +200,9 @@ impl Cheatcode for makePersistent_2Call {
impl Cheatcode for makePersistent_3Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { accounts } = self;
ccx.ecx.db.extend_persistent_accounts(accounts.iter().copied());
for account in accounts {
ccx.ecx.db.add_persistent_account(*account);
}
Ok(Default::default())
}
}
Expand All @@ -208,7 +218,9 @@ impl Cheatcode for revokePersistent_0Call {
impl Cheatcode for revokePersistent_1Call {
fn apply_full<DB: DatabaseExt>(&self, ccx: &mut CheatsCtxt<DB>) -> Result {
let Self { accounts } = self;
ccx.ecx.db.remove_persistent_accounts(accounts.iter().copied());
for account in accounts {
ccx.ecx.db.remove_persistent_account(account);
}
Ok(Default::default())
}
}
Expand Down
57 changes: 56 additions & 1 deletion crates/cheatcodes/src/fs.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
//! Implementations of [`Filesystem`](spec::Group::Filesystem) cheatcodes.

use super::string::parse;
use crate::{Cheatcode, Cheatcodes, Result, Vm::*};
use crate::{Cheatcode, Cheatcodes, CheatcodesExecutor, CheatsCtxt, Result, Vm::*};
use alloy_dyn_abi::DynSolType;
use alloy_json_abi::ContractObject;
use alloy_primitives::{hex, Bytes, U256};
use alloy_sol_types::SolValue;
use dialoguer::{Input, Password};
use foundry_common::fs;
use foundry_config::fs_permissions::FsAccessKind;
use foundry_evm_core::backend::DatabaseExt;
use revm::interpreter::CreateInputs;
use semver::Version;
use std::{
collections::hash_map::Entry,
Expand Down Expand Up @@ -262,6 +264,59 @@ impl Cheatcode for getDeployedCodeCall {
}
}

impl Cheatcode for deployCode_0Call {
fn apply_full_with_executor<DB: DatabaseExt, E: CheatcodesExecutor>(
&self,
ccx: &mut CheatsCtxt<DB>,
executor: &mut E,
) -> Result {
let Self { artifactPath: path } = self;
let bytecode = get_artifact_code(ccx.state, path, false)?;
let output = executor
.exec_create(
CreateInputs {
caller: ccx.caller,
scheme: revm::primitives::CreateScheme::Create,
value: U256::ZERO,
init_code: bytecode,
gas_limit: ccx.gas_limit,
},
ccx.state,
ccx.ecx,
)
.unwrap();

Ok(output.address.unwrap().abi_encode())
}
}

impl Cheatcode for deployCode_1Call {
fn apply_full_with_executor<DB: DatabaseExt, E: CheatcodesExecutor>(
&self,
ccx: &mut CheatsCtxt<DB>,
executor: &mut E,
) -> Result {
let Self { artifactPath: path, constructorArgs } = self;
let mut bytecode = get_artifact_code(ccx.state, path, false)?.to_vec();
bytecode.extend_from_slice(constructorArgs);
let output = executor
.exec_create(
CreateInputs {
caller: ccx.caller,
scheme: revm::primitives::CreateScheme::Create,
value: U256::ZERO,
init_code: bytecode.into(),
gas_limit: ccx.gas_limit,
},
ccx.state,
ccx.ecx,
)
.unwrap();

Ok(output.address.unwrap().abi_encode())
}
}

/// Returns the path to the json artifact depending on the input
///
/// Can parse following input formats:
Expand Down
Loading