Skip to content

Verbatim contracts #16027

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
cameel opened this issue Apr 27, 2025 · 1 comment
Open

Verbatim contracts #16027

cameel opened this issue Apr 27, 2025 · 1 comment
Labels
EOF high impact Changes are very prominent and affect users or the project in a major way. medium effort Default level of effort must have Something we consider an essential part of Solidity 1.0.

Comments

@cameel
Copy link
Member

cameel commented Apr 27, 2025

Abstract

Introduce syntax for defining EOF initcontainers produced from a verbatim string of bytecode rather than a contract definition. Allow eofcreate() to refer to them and deploy them that way.

contract A = hex"ef0001010004020001001103000100160400000000800002608060405234e100055f6080ee005f80fdef0001010004020001000304000000008000025f80fd"; // contract A {}

contract C {
    function deploy() public {
        assembly {
            eofcreate(A.object, 1, 2, 3, 4)
        }
    }
}

Motivation

Due to the ban on code introspection, eofcreate(), unlike create() or create2() does not allow the user to provide arbitrary bytecode to be deployed. While this is intentional, there are use cases that are not in conflict with the ban but can no longer be expressed in the language due to this. For example libraries implementing ERC-1167 depend on the ability to deploy a piece of hand-crafted bytecode that is known at compilation time. We need a language construct to express that.

The solution is to make the compiler aware that the hard-coded bytecode is not just a random string of bytes, but is instead meant to represent a valid initcontainer. Currently the subcontainers produced from Solidity source always correspond to contracts (either the runtime part of the current contract or other contracts it has a bytecode dependency on), but this mechanism can be extended to allow hand-crafted containers.

Note that this does not have the same negative implications as allowing embedding of pieces of verbatim bytecode inside contracts (#12067). The container would be expected to be a self-contained contract and would not undergo any optimization.

Specification

  • The bytecode is used as-is to create a subcontainer owned by every contract that references it.
    • There is no validation. We rely on the validation performed by the EVM at deployment time.
    • There is no optimization of any kind.
    • The position inside the parent container is an implementation detail.
  • At Solidity level, introduce the contract X = <bytecode>; syntax, where <bytecode> is a string literal.
    • The container becomes a fourth kind of contract (currently there are 3: contract, interface, library). This kind of contract cannot be deployed with new (we don't know the constructor signature), but can be used as any other type. In particular, most properties of type(X) are available and it can be cast to an interface.
    • The bytecode can be referenced as <name>.object.
      • This is the syntax that eof: Enable eofcreate inline assembly #15981 already introduces for referring to contracts in eofcreate().
      • This is only allowed in inline assembly.
      • The value is a compile-time constant, semantically behaving as a literal argument.
        • We introduce a new type of a literal argument that represents verbatim bytecode.
          • That type could also be used in other places, e.g. in verbatim(), and would be treated as distinct form other literal strings.
  • At Yul level, there are two ways we could enable this:
    1. Allow passing verbatim bytecode in the form of a literal argument of verbatim bytecode type directly into eofcreate().
      • Internally, this triggers creation of a new subcontainer for each distinct piece of bytecode.
    2. Allow defining objects as literal bytecode
      • The syntax could mimic the way data is currently defined inside objects:
        object X = hex"...";
      • This is generally a cleaner solution, because it retains the property that the Yul object structure reflects the structure of the bytecode. Every subcontainer has a corresponding object and objects are not implicitly created based on arguments to some instructions.

The feature is primarily meant for EOF and at least the initial implementation should focus on that. It would technically also be possible to extend it to the legacy EVM, but this would require introducing additional inline assembly builtins corresponding to create() and create2() that would accept verbatim bytecode corresponding to a contract.

Backwards Compatibility

Fully backwards compatible outside of Yul/inline assembly. Changes to eofcreate() would be incompatible, but EOF is an experimental feature and we don't guarantee compatibility for those until they become stable.

@cameel cameel added EOF high impact Changes are very prominent and affect users or the project in a major way. medium effort Default level of effort must have Something we consider an essential part of Solidity 1.0. labels Apr 27, 2025
@cameel
Copy link
Member Author

cameel commented Apr 27, 2025

Some open questions:

  • Should we require hex"" strings for the bytecode or allow any kind of string?
  • Would it be better to introduce something new instead of reusing the contract keyword? E.g. container.
    • This would be a breaking change though, at least outside of EOF.
    • contract seems like a good fit to me. Containers in essence represent contacts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
EOF high impact Changes are very prominent and affect users or the project in a major way. medium effort Default level of effort must have Something we consider an essential part of Solidity 1.0.
Projects
None yet
Development

No branches or pull requests

1 participant