Skip to content

Commit

Permalink
feat: add --broadcast flag to forge create, default to dry run mode (
Browse files Browse the repository at this point in the history
…foundry-rs#9420)

* add --broadcast flag to forge create, default to dry run

* nits

* fix tests

* add dry run tests incl --json

* minor fixes, failing test due to minor bytecode difference
  • Loading branch information
zerosnacks authored and rplusq committed Nov 29, 2024
1 parent da930e8 commit 70528b3
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 6 deletions.
37 changes: 36 additions & 1 deletion crates/forge/bin/cmd/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ pub struct CreateArgs {
)]
constructor_args_path: Option<PathBuf>,

/// Broadcast the transaction.
#[arg(long)]
pub broadcast: bool,

/// Verify contract after creation.
#[arg(long)]
verify: bool,
Expand Down Expand Up @@ -155,6 +159,10 @@ impl CreateArgs {
} else {
provider.get_chain_id().await?
};

// Whether to broadcast the transaction or not
let dry_run = !self.broadcast;

if self.unlocked {
// Deploy with unlocked account
let sender = self.eth.wallet.from.expect("required");
Expand All @@ -167,6 +175,7 @@ impl CreateArgs {
sender,
config.transaction_timeout,
id,
dry_run,
)
.await
} else {
Expand All @@ -185,6 +194,7 @@ impl CreateArgs {
deployer,
config.transaction_timeout,
id,
dry_run,
)
.await
}
Expand Down Expand Up @@ -260,6 +270,7 @@ impl CreateArgs {
deployer_address: Address,
timeout: u64,
id: ArtifactId,
dry_run: bool,
) -> Result<()> {
let bin = bin.into_bytes().unwrap_or_else(|| {
panic!("no bytecode found in bin object for {}", self.contract.name)
Expand Down Expand Up @@ -339,6 +350,30 @@ impl CreateArgs {
self.verify_preflight_check(constructor_args.clone(), chain, &id).await?;
}

if dry_run {
if !shell::is_json() {
sh_warn!("Dry run enabled, not broadcasting transaction\n")?;

sh_println!("Contract: {}", self.contract.name)?;
sh_println!(
"Transaction: {}",
serde_json::to_string_pretty(&deployer.tx.clone())?
)?;
sh_println!("ABI: {}\n", serde_json::to_string_pretty(&abi)?)?;

sh_warn!("To broadcast this transaction, add --broadcast to the previous command. See forge create --help for more.")?;
} else {
let output = json!({
"contract": self.contract.name,
"transaction": &deployer.tx,
"abi":&abi
});
sh_println!("{}", serde_json::to_string_pretty(&output)?)?;
}

return Ok(());
}

// Deploy the actual contract
let (deployed_contract, receipt) = deployer.send_with_receipt().await?;

Expand All @@ -349,7 +384,7 @@ impl CreateArgs {
"deployedTo": address.to_string(),
"transactionHash": receipt.transaction_hash
});
sh_println!("{output}")?;
sh_println!("{}", serde_json::to_string_pretty(&output)?)?;
} else {
sh_println!("Deployer: {deployer_address}")?;
sh_println!("Deployed to: {address}")?;
Expand Down
129 changes: 124 additions & 5 deletions crates/forge/tests/cli/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use anvil::{spawn, NodeConfig};
use foundry_compilers::artifacts::{remappings::Remapping, BytecodeHash};
use foundry_config::Config;
use foundry_test_utils::{
forgetest, forgetest_async, str,
forgetest, forgetest_async,
snapbox::IntoData,
str,
util::{OutputExt, TestCommand, TestProject},
};
use std::str::FromStr;
Expand Down Expand Up @@ -145,6 +147,7 @@ forgetest_async!(can_create_template_contract, |prj, cmd| {
let config = Config { bytecode_hash: BytecodeHash::None, ..Default::default() };
prj.write_config(config);

// Dry-run without the `--broadcast` flag
cmd.forge_fuse().args([
"create",
format!("./src/{TEMPLATE_CONTRACT}.sol:{TEMPLATE_CONTRACT}").as_str(),
Expand All @@ -154,20 +157,131 @@ forgetest_async!(can_create_template_contract, |prj, cmd| {
pk.as_str(),
]);

// Dry-run
cmd.assert().stdout_eq(str![[r#"
[COMPILING_FILES] with [SOLC_VERSION]
[SOLC_VERSION] [ELAPSED]
Compiler run successful!
Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
[TX_HASH]
Contract: Counter
Transaction: {
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"to": null,
"maxFeePerGas": "0x77359401",
"maxPriorityFeePerGas": "0x1",
"gas": "0x17575",
"input": "[..]",
"nonce": "0x0",
"chainId": "0x7a69"
}
ABI: [
{
"type": "function",
"name": "increment",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "number",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "setNumber",
"inputs": [
{
"name": "newNumber",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
}
]
"#]]);

// Dry-run with `--json` flag
cmd.arg("--json").assert().stdout_eq(
str![[r#"
{
"contract": "Counter",
"transaction": {
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"to": null,
"maxFeePerGas": "0x77359401",
"maxPriorityFeePerGas": "0x1",
"gas": "0x17575",
"input": "[..]",
"nonce": "0x0",
"chainId": "0x7a69"
},
"abi": [
{
"type": "function",
"name": "increment",
"inputs": [],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"type": "function",
"name": "number",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"type": "function",
"name": "setNumber",
"inputs": [
{
"name": "newNumber",
"type": "uint256",
"internalType": "uint256"
}
],
"outputs": [],
"stateMutability": "nonpayable"
}
]
}
"#]]
.is_json(),
);

cmd.forge_fuse().args([
"create",
format!("./src/{TEMPLATE_CONTRACT}.sol:{TEMPLATE_CONTRACT}").as_str(),
"--rpc-url",
rpc.as_str(),
"--private-key",
pk.as_str(),
"--broadcast",
]);

cmd.assert().stdout_eq(str![[r#"
No files changed, compilation skipped
Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Deployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
[TX_HASH]
"#]]);
Expand All @@ -193,6 +307,7 @@ forgetest_async!(can_create_using_unlocked, |prj, cmd| {
"--from",
format!("{dev:?}").as_str(),
"--unlocked",
"--broadcast",
]);

cmd.assert().stdout_eq(str![[r#"
Expand All @@ -204,6 +319,7 @@ Deployed to: 0x5FbDB2315678afecb367f032d93F642f64180aa3
[TX_HASH]
"#]]);

cmd.assert().stdout_eq(str![[r#"
No files changed, compilation skipped
Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Expand Down Expand Up @@ -248,6 +364,7 @@ contract ConstructorContract {
rpc.as_str(),
"--private-key",
pk.as_str(),
"--broadcast",
"--constructor-args",
"My Constructor",
])
Expand Down Expand Up @@ -285,6 +402,7 @@ contract TupleArrayConstructorContract {
rpc.as_str(),
"--private-key",
pk.as_str(),
"--broadcast",
"--constructor-args",
"[(1,2), (2,3), (3,4)]",
])
Expand Down Expand Up @@ -335,6 +453,7 @@ contract UniswapV2Swap {
rpc.as_str(),
"--private-key",
pk.as_str(),
"--broadcast",
])
.assert_success()
.stdout_eq(str![[r#"
Expand Down

0 comments on commit 70528b3

Please sign in to comment.