Skip to content

Commit

Permalink
fix: resolve constructor args (#6153)
Browse files Browse the repository at this point in the history
* test: add constructor args test

* clippy

* use resolve

* fix input resolve
  • Loading branch information
mattsse authored Oct 27, 2023
1 parent 4422d67 commit f5b9c02
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 18 deletions.
64 changes: 46 additions & 18 deletions crates/forge/bin/cmd/create.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use super::{retry::RetryArgs, verify};
use alloy_dyn_abi::{DynSolType, DynSolValue, JsonAbiExt};
use alloy_dyn_abi::{DynSolValue, JsonAbiExt, ResolveSolType};
use alloy_json_abi::{Constructor, JsonAbi as Abi};
use alloy_primitives::{Address, Bytes};
use clap::{Parser, ValueHint};
use ethers::{
abi::InvalidOutputType,
contract::ContractError,
prelude::{Middleware, MiddlewareBuilder},
types::{transaction::eip2718::TypedTransaction, Chain},
types::{
transaction::eip2718::TypedTransaction, BlockNumber, Chain, Eip1559TransactionRequest,
TransactionReceipt, TransactionRequest,
},
};
use eyre::{Context, Result};
use foundry_cli::{
Expand All @@ -17,7 +21,7 @@ use foundry_common::{abi::parse_tokens, compile, estimate_eip1559_fees};
use foundry_compilers::{artifacts::BytecodeObject, info::ContractInfo, utils::canonicalized};
use foundry_utils::types::{ToAlloy, ToEthers};
use serde_json::json;
use std::{path::PathBuf, sync::Arc};
use std::{borrow::Borrow, marker::PhantomData, path::PathBuf, sync::Arc};

/// CLI arguments for `forge create`.
#[derive(Debug, Clone, Parser)]
Expand Down Expand Up @@ -320,29 +324,28 @@ impl CreateArgs {
verify.run().await
}

/// Parses the given constructor arguments into a vector of `DynSolValue`s, by matching them
/// against the constructor's input params.
///
/// Returns a list of parsed values that match the constructor's input params.
fn parse_constructor_args(
&self,
constructor: &Constructor,
constructor_args: &[String],
) -> Result<Vec<DynSolValue>> {
let params = constructor
.inputs
.iter()
.zip(constructor_args)
.map(|(input, arg)| (DynSolType::parse(&input.ty).expect("Could not parse types"), arg))
.collect::<Vec<_>>();
let params_2 = params.iter().map(|(ty, arg)| (ty, arg.as_str())).collect::<Vec<_>>();
parse_tokens(params_2)
let mut params = Vec::with_capacity(constructor.inputs.len());
for (input, arg) in constructor.inputs.iter().zip(constructor_args) {
// resolve the input type directly
let ty = input
.resolve()
.wrap_err_with(|| format!("Could not resolve constructor arg: input={input}"))?;
params.push((ty, arg));
}
let params = params.iter().map(|(ty, arg)| (ty, arg.as_str()));
parse_tokens(params)
}
}

use ethers::{
contract::ContractError,
types::{BlockNumber, Eip1559TransactionRequest, TransactionReceipt, TransactionRequest},
};

use std::{borrow::Borrow, marker::PhantomData};

/// `ContractFactory` is a [`DeploymentTxFactory`] object with an
/// [`Arc`] middleware. This type alias exists to preserve backwards
/// compatibility with less-abstract Contracts.
Expand Down Expand Up @@ -598,4 +601,29 @@ mod tests {
]);
assert_eq!(args.chain_id(), Some(9999));
}

#[test]
fn test_parse_constructor_args() {
let args: CreateArgs = CreateArgs::parse_from([
"foundry-cli",
"src/Domains.sol:Domains",
"--constructor-args",
"Hello",
]);
let constructor: Constructor = serde_json::from_str(r#"{"type":"constructor","inputs":[{"name":"_name","type":"string","internalType":"string"}],"stateMutability":"nonpayable"}"#).unwrap();
let params = args.parse_constructor_args(&constructor, &args.constructor_args).unwrap();
assert_eq!(params, vec![DynSolValue::String("Hello".to_string())]);
}

#[test]
fn test_parse_tuple_constructor_args() {
let args: CreateArgs = CreateArgs::parse_from([
"foundry-cli",
"src/Domains.sol:Domains",
"--constructor-args",
"[(1,2), (2,3), (3,4)]",
]);
let constructor: Constructor = serde_json::from_str(r#"{"type":"constructor","inputs":[{"name":"_points","type":"tuple[]","internalType":"struct Point[]","components":[{"name":"x","type":"uint256","internalType":"uint256"},{"name":"y","type":"uint256","internalType":"uint256"}]}],"stateMutability":"nonpayable"}"#).unwrap();
let _params = args.parse_constructor_args(&constructor, &args.constructor_args).unwrap();
}
}
37 changes: 37 additions & 0 deletions crates/forge/tests/cli/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,5 +267,42 @@ contract ConstructorContract {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures/can_create_with_constructor_args.stdout"),
);

prj.inner()
.add_source(
"TupleArrayConstructorContract",
r#"
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
struct Point {
uint256 x;
uint256 y;
}
contract TupleArrayConstructorContract {
constructor(Point[] memory _points) {}
}
"#,
)
.unwrap();

cmd.forge_fuse().args([
"create",
"./src/TupleArrayConstructorContract.sol:TupleArrayConstructorContract",
"--use",
"solc:0.8.15",
"--rpc-url",
rpc.as_str(),
"--private-key",
pk.as_str(),
"--constructor-args",
"[(1,2), (2,3), (3,4)]",
]);

cmd.unchecked_output().stdout_matches_path(
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests/fixtures/can_create_with_tuple_constructor_args.stdout"),
);
}
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Compiling 1 files with 0.8.15
Solc 0.8.15 finished in 26.44ms
Compiler run successful!
Deployer: 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
Deployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
Transaction hash: 0x69625b76d83634603a9dbc5b836ef89bafdd9fc7c180fc6d636c5088353cf501

0 comments on commit f5b9c02

Please sign in to comment.