Skip to content

Commit c419100

Browse files
gakonstampagentzerosnackszerosnacksdecofe
authored
feat(forge): specify compilation profile in vm.getCode (foundry-rs#13191)
* feat(forge): specify compilation profile in vm.getCode Add support for specifying a compilation profile in artifact path parsing for vm.getCode, vm.getDeployedCode, and vm.deployCode cheatcodes. This allows users with multiple compilation profiles in foundry.toml to select specific artifact versions. For example: - `vm.getCode("Contract.sol:v1")` - `vm.getCode("Contract.sol:ContractName:optimized")` The feature distinguishes between semver versions (like 0.8.23) and profile names (like v1, optimized) by attempting to parse the suffix as a version first. Closes foundry-rs#12821 * fix: address clippy warnings - Combine duplicate if branches for version detection - Remove needless ref borrow in profile comparison * test: add unit tests for artifact path parsing and profile support - Refactor parsing logic into reusable parse_artifact_path function - Add 11 unit tests covering all artifact path formats: - file only, file+contract, file+contract+version, file+contract+profile - file+version, contract only, contract+version, contract+profile - Various profile name patterns (v1, v2, paris, optimized, etc.) - Add Solidity integration test for profile-based getCode * test: add multi-profile test demonstrating different bytecode per profile Add comprehensive tests showing that vm.getCode correctly retrieves different bytecode for different compilation profiles: - Create testdata/multi-profile/ with Counter contract compiled using 'default', 'optimized' (10000 runs), and 'unoptimized' (no optimizer) profiles - Add tests verifying: - Different profiles produce different bytecode - vm.getCode('Contract:profile') works correctly - vm.getCode('path/to/Contract.sol:Contract:profile') works correctly - vm.deployCode with profile works - vm.getDeployedCode with profile works - Non-existent profiles fail appropriately * style: fix rustfmt formatting * style: fix forge fmt formatting in Solidity test * fix: simplify multi-profile tests to verify parsing behavior - Remove invalid 'profiles' field from compilation_restrictions - Use assertTrue instead of assertNotEq (not available in DSTest) - Simplify tests to verify profile parsing works with default profile - Test that non-existent profiles fail appropriately * fix: restore multi-profile compilation restriction in foundry.toml * fix: rename Counter to ProfileCounter to avoid artifact name collision The multi-version tests use a contract named Counter, causing conflicts when my multi-profile tests also used Counter. * fix: remove multi-profile Solidity test to avoid breaking existing tests The additional_compiler_profiles cause all contracts to be compiled with multiple profiles, which breaks the existing multi-version tests that rely on version-based disambiguation. The unit tests for artifact path parsing adequately test the profile feature at the parsing level. End-to-end testing of profile-based selection requires a more complex test setup. * test: add profile-based getCode test using existing paris profile Add test demonstrating vm.getCode with profile selection using the existing paris compilation profile. Tests: - vm.getCode("path:Contract:paris") format - vm.getCode("Contract:paris") format - vm.getDeployedCode and vm.deployCode with profile - Error when using non-existent profile - Error when requesting wrong profile for a contract This test uses the existing paris profile which is already scoped to paris/** files, avoiding conflicts with other multi-version tests. Amp-Thread-ID: https://ampcode.com/threads/T-019bea01-185e-7079-990e-f33585663be2 Co-authored-by: Amp <amp@ampcode.com> * test: add multi-profile test with proper disambiguation fix Fix the artifact disambiguation logic to not filter by running_artifact's version/profile when user has explicitly specified those criteria. This allows adding global additional_compiler_profiles without breaking existing tests. Changes: - Fix disambiguation: only use running_artifact's version for filtering when user did NOT specify a version in the artifact path - Same fix for profile filtering - Add 'optimized' and 'unoptimized' profiles to testdata/foundry.toml - Add GetCodeMultiProfile.t.sol demonstrating that different profiles produce different bytecode and can be selected via vm.getCode The test verifies: - vm.getCode("Contract:optimized") returns different bytecode than vm.getCode("Contract:unoptimized") - vm.deployCode and vm.getDeployedCode work with profile selection - Non-existent profiles fail appropriately Amp-Thread-ID: https://ampcode.com/threads/T-019bea01-185e-7079-990e-f33585663be2 Co-authored-by: Amp <amp@ampcode.com> * fix: use require instead of assertNotEq for bytes32 comparison assertNotEq doesn't have an overload for bytes32, use require with != instead * fix: resolve CI failures for profile-based artifact selection Changes: - Remove GetCodeMultiProfile.t.sol test that expected artifacts compiled with 'optimized' and 'unoptimized' profiles without corresponding compilation_restrictions - Remove unused 'optimized' and 'unoptimized' profiles from foundry.toml (the paris profile remains as it has proper restrictions) - Update multi-version tests to use full paths (multi-version/Counter.sol) to avoid ambiguity with other Counter contracts in testdata that would cause 'multiple matching artifacts found' error Amp-Thread-ID: https://ampcode.com/threads/T-019bea8a-abde-7172-9b50-efb0569a8222 Co-authored-by: Amp <amp@ampcode.com> * fix fmt * fix getCode file profile lookup * fix: prefer contract name for ambiguous getCode artifact paths --------- Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: zerosnacks <zerosnacks@protonmail.com> Co-authored-by: zerosnacks <95942363+zerosnacks@users.noreply.github.com> Co-authored-by: Derek <256792747+decofe@users.noreply.github.com> Co-authored-by: Centaur AI <ai@centaur.local> Co-authored-by: Mablr <59505383+mablr@users.noreply.github.com> Co-authored-by: grandizzy <38490174+grandizzy@users.noreply.github.com>
1 parent 6255cde commit c419100

7 files changed

Lines changed: 424 additions & 90 deletions

File tree

crates/cheatcodes/assets/cheatcodes.json

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/cheatcodes/spec/src/vm.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,72 +1998,83 @@ interface Vm {
19981998
function getArtifactPathByDeployedCode(bytes calldata deployedCode) external view returns (string memory path);
19991999

20002000
/// Gets the creation bytecode from an artifact file. Takes in the relative path to the json file or the path to the
2001-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2001+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2002+
/// <version>/<profile> parts are optional. Use <profile> to select artifacts compiled with a specific profile
2003+
/// from foundry.toml.
20022004
#[cheatcode(group = Filesystem)]
20032005
function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode);
20042006

20052007
/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
2006-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2008+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2009+
/// <version>/<profile> parts are optional.
20072010
/// Reverts if the target artifact contains unlinked library placeholders.
20082011
#[cheatcode(group = Filesystem)]
20092012
function deployCode(string calldata artifactPath) external returns (address deployedAddress);
20102013

20112014
/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
2012-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2015+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2016+
/// <version>/<profile> parts are optional.
20132017
/// Reverts if the target artifact contains unlinked library placeholders.
20142018
///
20152019
/// Additionally accepts abi-encoded constructor arguments.
20162020
#[cheatcode(group = Filesystem)]
20172021
function deployCode(string calldata artifactPath, bytes calldata constructorArgs) external returns (address deployedAddress);
20182022

20192023
/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
2020-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2024+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2025+
/// <version>/<profile> parts are optional.
20212026
/// Reverts if the target artifact contains unlinked library placeholders.
20222027
///
20232028
/// Additionally accepts `msg.value`.
20242029
#[cheatcode(group = Filesystem)]
20252030
function deployCode(string calldata artifactPath, uint256 value) external returns (address deployedAddress);
20262031

20272032
/// Deploys a contract from an artifact file. Takes in the relative path to the json file or the path to the
2028-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2033+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2034+
/// <version>/<profile> parts are optional.
20292035
/// Reverts if the target artifact contains unlinked library placeholders.
20302036
///
20312037
/// Additionally accepts abi-encoded constructor arguments and `msg.value`.
20322038
#[cheatcode(group = Filesystem)]
20332039
function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value) external returns (address deployedAddress);
20342040

20352041
/// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the
2036-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2042+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2043+
/// <version>/<profile> parts are optional.
20372044
/// Reverts if the target artifact contains unlinked library placeholders.
20382045
#[cheatcode(group = Filesystem)]
20392046
function deployCode(string calldata artifactPath, bytes32 salt) external returns (address deployedAddress);
20402047

20412048
/// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the
2042-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2049+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2050+
/// <version>/<profile> parts are optional.
20432051
/// Reverts if the target artifact contains unlinked library placeholders.
20442052
///
20452053
/// Additionally accepts abi-encoded constructor arguments.
20462054
#[cheatcode(group = Filesystem)]
20472055
function deployCode(string calldata artifactPath, bytes calldata constructorArgs, bytes32 salt) external returns (address deployedAddress);
20482056

20492057
/// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the
2050-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2058+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2059+
/// <version>/<profile> parts are optional.
20512060
/// Reverts if the target artifact contains unlinked library placeholders.
20522061
///
20532062
/// Additionally accepts `msg.value`.
20542063
#[cheatcode(group = Filesystem)]
20552064
function deployCode(string calldata artifactPath, uint256 value, bytes32 salt) external returns (address deployedAddress);
20562065

20572066
/// Deploys a contract from an artifact file, using the CREATE2 salt. Takes in the relative path to the json file or the path to the
2058-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2067+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2068+
/// <version>/<profile> parts are optional.
20592069
/// Reverts if the target artifact contains unlinked library placeholders.
20602070
///
20612071
/// Additionally accepts abi-encoded constructor arguments and `msg.value`.
20622072
#[cheatcode(group = Filesystem)]
20632073
function deployCode(string calldata artifactPath, bytes calldata constructorArgs, uint256 value, bytes32 salt) external returns (address deployedAddress);
20642074

20652075
/// Gets the deployed bytecode from an artifact file. Takes in the relative path to the json file or the path to the
2066-
/// artifact in the form of <path>:<contract>:<version> where <contract> and <version> parts are optional.
2076+
/// artifact in the form of <path>:<contract>:<version> or <path>:<contract>:<profile> where <contract> and
2077+
/// <version>/<profile> parts are optional.
20672078
#[cheatcode(group = Filesystem)]
20682079
function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode);
20692080

0 commit comments

Comments
 (0)