Skip to content

feat(cheatcodes): Add cheatcode that allows intercepting initcode from a normal create #10176

@Philogy

Description

@Philogy

Component

Forge

Proposal

Add cheatcode that lets you hook into Solidity's built-in new <ContractName>(...constructorArgs) syntax to retrieve the initcode. This will ensure that it's easy and type-safe for developers to construct and access the initcode payload. This can be achieved via the addition of a single new cheatcode: vm.interceptInitcode().

Upon invocation this cheatcode would cause the very next create/create2 to fail setting the returndata buffer (error data) to the initcode. Interacting with this opcode to get the initcode would then look like this:

vm.interceptInitcode();
bytes memory initcode;
try new MyContract(param1, param2) { assert(false); /* optional: Makes use of cheatcode more explicit */ }
catch (bytes memory interceptedInitcode) { initcode = interceptedInitcode; }

Motivation

In foundry scripts the primary action is deploying contracts. In many contexts this is done via create factories like the well-known CREATE2 factory, @pcaversaccio CreateX or my own Create3 based deploy factory "SubZero". In all these cases developers need access to their contract's initcode inside their script and sometimes tests.

Foundry & Solidity already give you several ways of accessing creationCode via either vm.getCode(<artifactName>) or Solidity's type(ContractName).creationCode the issue arrises when wanting to access the initcode payload which is the creationCode together with the correctly encoded constructor arguments.

The only way to achieve this currently is to manually encode and concatenate the creation code and the constructor arguments. This is sub-optimal as it is not type-safe and can lead to errors/bugs if the script and contract ever get out-of-sync:

bytes memory initcode = abi.encodePacked(type(VanityMarket).creationCode, abi.encode(MARKET_OWNER));

This is error prone, leading to errors/corrupted initcode data when the contract implementation and script diverge.

Spec

  • Add interceptingNext: bool flag to cheatcodes
  • Add vm.interceptInitcode cheatcode, sets interceptNext to true if false, gives an error otherwise
  • Add create/create2 inspector. Upon a create invocation, if interceptNext = true, set to false and cause an immediate revert returning the create initcode as error data in the returndata buffer. Otherwise if interceptNext = false proceed with normal EVM create/create2 semantics

Rationale

Shouldn't this be a Solidity Feature?

Yes, but considering how fast Solidity moves and that this doesn't seem like a huge change in foundry, only adding a single cheatcode, I think it's a worthwhile extension.

Why so verbose, why not 1 cheatcode for activating the intercept and another for retrieving the intercept?

The proposed design ensures minimal additions in terms of opcodes and also makes it explicit when you're actually deploying a contract vs. retrieving the initcode. This minimizes the potential footgun of accidentally deploying an additional/unwanted contract in your scripts/test when you refactor code.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions