Discussion topic for EIP-7620: EOF - Contract Creation Instructions.
EIP-7620 adds CREATE3/4
EOFCREATE
and TXCREATE
opcodes and EOF contract creation specs, as previously specced out in the “Mega EOF Endgame” spec (aka “Megaspec”).
Discussion topic for EIP-7620: EOF - Contract Creation Instructions.
EIP-7620 adds CREATE3/4
EOFCREATE
and TXCREATE
opcodes and EOF contract creation specs, as previously specced out in the “Mega EOF Endgame” spec (aka “Megaspec”).
Hi, have you considered that “CREATE3 opcode” will collide in naming with CREATE+CREATE2 combos named as CREATE3?
This will confuse new devs reading older hints / tutorials / SO.
Since these opcodes are for EOF contracts, while CREATE and CREATE2 are not to be used, it might make sense to discontinue sequence in naming, as well.
CREATE3/4 is just temporary naming which kind of sunk in. Renaming is still an option, good point about the other CREATE3 here.
@pdobacz is there a rationale behind having the order of the stack inputs for EOFCREATE
be value
, salt
, input_offset
, input_size
, instead of value
, input_offset
, input_size
, salt
(like in CREATE2)?
I don’t know, I’ll ask around if there was any specific rationale.
EOFCREATE input isn’t exactly the same as CREATE2 input (calldata vs initcode), though I don’t think this was the reason.
This EIP seems like it would cut off use cases where a factory contract CREATE
’s a contract from calldata. As an example, here’s some Yul code that would have no equivalent after 7620:
let ptr := mload(0x40)
calldatacopy(ptr, initcode.offset, initcode.length)
new_contract := create2(callvalue(), ptr, initcode.length, salt)
That seems like a pretty important use case, and if not supported it would preclude my adoption of EOF. Combined with the prohibition of legacy contracts creating EOF contracts, this would also mean that deterministic, permissionless deployment of trusted contracts to the same address across all chains (using something like Nick’s method or the Arachnid deterministic deployment proxy) no longer works. I expect that for many protocols this would be a blocker to adopting EOF.
It is by design – there is a specific requirement that contract code cannot be inspected within the EVM, and your use case basically allows that.
This is solved by TXCREATE.
Ahh, TXCREATE
solves that problem pretty neatly. I hope it goes in at the same time as the rest of EOF to enable that use case. To explain in more detail my specific use case, I have 2 considerations:
CREATE2
and EOFCREATE
obviously enable trustlessness by deriving the contract address from the hash of the initcode. However, permissionlessness is more difficult. Using TXCREATE
in combination with Nick’s method for deployment gives us permissionlessness. We can imagine an EOF replacement for the Arachnid deterministic deployment proxy that uses TXCREATE
instead of CALLDATACOPY ... CREATE2
to obtain the same effect.In my specific use case, I rely on the Safe{Wallet}'s stack, which in turn depends on a CREATE2
factory toehold contract. This toehold contract can be either the Arachnid deterministic deployment proxy (permissionless, somewhat more fragile) or the Safe singleton factory (not permissionless, but more robust). I’ve been bitten by the lack of permissionlessness in the Safe singleton factory, which is why I care about using Nick’s method in combination with TXCREATE
. Of course, on chains with extreme gas rules (e.g. Mantle), this isn’t foolproof, but we’re not letting perfect be the enemy of good.
TXCREATE
, but we would still need a non-salted contract creation opcode to make it work without doing something really crazy. TXCREATE
solves the problem of being able to factory-deploy from initcode not known to the factory at deploy-time, but the problem of non-salted deployment (i.e. CREATE
; deployee addresses derived from the deployer address and its nonce) remains unsolved.This pertains to the Deployer
contract for 0x’s DEX aggregation router. This router contract is iterated rapidly to accommodate the shifting liquidity landscape; each iteration requires redeployment. This Deployer
factory contract uses a “CREATE3” pattern to deploy the router to an address derived only from a feature identifier (there’s more than 1 router, each with a different feature set) and a nonce specific to that feature identifier. This lets 0x’s integrators precompute future router contract addresses for their own on-chain properties. Obviously, even though the router is trust-minimized, deployment is permissioned. I can sort of vaguely imagine a solution involving the abuse of ecrecover
to compute addresses based on a feature++nonce and a secp256k1 pubkey and then deriving the deployed contract from that. That would also sacrifice a degree of trustlessness, unless you want to throw some MPC into the mix, which is not very satisfactory.
If the address derivation did not include the hash of the initcode, would this negatively impact counterfactual patterns? My understanding is that create3 uses patterns used by polymorphic addresses, which circumvents the initcode hash of the CREATE2 contract.
Is the certainty of the address more important than a sure knowledge of the code in that address?
The way “CREATE3” patterns work, you very much have to opt-in to avoiding initcode dependence in address calculations. Polymorphism is dead now that SELFDESTRUCT
only works in the same transaction. It’s not practical to stumble your way into an address that doesn’t depend on the initcode deploying it when what you wanted was a counterfactual address. Plus EOA-deployed contracts are still derived from the nonce of the deployer, so there’s not really any getting around that.
That’s the point of the “toehold contract” - either via Nick’s method or a specific account?
If the initcode hash was removed from EOFCREATE or TXCREATE (relying on the sender address and a specified salt only) would that suit your needs?
Do you have any requirements that need the initcode hash in the address derivation?
Also, would EIP-7819: Create delegate be a possible solution? It’s EIP-7702, but for contract accounts.