pcaversaccio / createx

Factory smart contract to make easier and safer usage of the `CREATE` and `CREATE2` EVM opcodes as well as of `CREATE3`-based (i.e. without an initcode factor) contract creations.
https://createx.rocks
GNU Affero General Public License v3.0
304 stars 18 forks source link

💥 Add Presign and Deployment Script #31

Closed pcaversaccio closed 10 months ago

pcaversaccio commented 10 months ago

🕓 Changelog

This PR adds an ethers/hardhat-based pre-signing and deployment script for the contract creation transaction of CreateX.

It's as simple - using a personal test account - as the following (another way of course to be documented later is by using cast):

image

image

Example deployment: 0x9a30661B895f94d4A75Bd438E98b5Ae219620d50

PS: This obviously only works for RPCs / networks that support pre-EIP-155 transactions.

Other Changes

🐶 Cute Animal Picture

image

github-actions[bot] commented 10 months ago

Coverage after merging sign-script into main will be

100.00%

Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
src
   CreateX.sol100%100%100%100%
pcaversaccio commented 10 months ago

In general this all seems good. One question I have is: once the code is frozen, how can we ensure we always deploy identical bytecode? For example, perhaps the scripts here should never compile the contract, and instead should read from a build artifact that we commit to the repo

Right, so to emphasise, these scripts will be amended/refactored once we freeze the code. The reason why for example the presign.ts script compiles is that I haven't added (yet) the --no-compile option to the command npx hardhat run --no-compile scripts/presign.ts, which makes local testing much easier. I actually plan to add to all npx hardhat run commands the --no-compile option, for the presign.ts script I will hardcode the initcode in a separate file (after confirming with you the validity) and will add an additional check in the script as well as in CI that the keccak256 hash of the initcode always matches. For the deploy.ts script, I will also add the --no-compile option to all scripts, will add a sanity check that the keccak256 hash of the presigned transaction always matches for deploying a raw transaction, and for the deployNormal function I will use instead the getContractFactory(abi: any[], bytecode: ethers.utils.BytesLike, signer?: ethers.Signer): Promise<ethers.ContractFactory> method for deploying and will hardcode the abi & initcode for this as well. For the verification part, I will also need to upload the build information so it can be used without compilation.

async function deployNormal() {
  const abi = [
    "error FailedContractCreation(address)",
    "error FailedContractInitialisation(address,bytes)",
    "error FailedEtherTransfer(address,bytes)",
    "error InvalidNonceValue(address)",
    "error InvalidSalt(address)",
    "event ContractCreation(address indexed,bytes32 indexed)",
    "event ContractCreation(address indexed)",
    "event Create3ProxyContractCreation(address indexed,bytes32 indexed)",
    "function computeCreate2Address(bytes32,bytes32) view returns (address)",
    "function computeCreate2Address(bytes32,bytes32,address) pure returns (address)",
    "function computeCreate3Address(bytes32,address) pure returns (address)",
    "function computeCreate3Address(bytes32) view returns (address)",
    "function computeCreateAddress(uint256) view returns (address)",
    "function computeCreateAddress(address,uint256) view returns (address)",
    "function deployCreate(bytes) payable returns (address)",
    "function deployCreate2(bytes32,bytes) payable returns (address)",
    "function deployCreate2(bytes) payable returns (address)",
    "function deployCreate2AndInit(bytes32,bytes,bytes,tuple(uint256,uint256),address) payable returns (address)",
    "function deployCreate2AndInit(bytes,bytes,tuple(uint256,uint256)) payable returns (address)",
    "function deployCreate2AndInit(bytes,bytes,tuple(uint256,uint256),address) payable returns (address)",
    "function deployCreate2AndInit(bytes32,bytes,bytes,tuple(uint256,uint256)) payable returns (address)",
    "function deployCreate2Clone(bytes32,address,bytes) payable returns (address)",
    "function deployCreate2Clone(address,bytes) payable returns (address)",
    "function deployCreate3(bytes) payable returns (address)",
    "function deployCreate3(bytes32,bytes) payable returns (address)",
    "function deployCreate3AndInit(bytes32,bytes,bytes,tuple(uint256,uint256)) payable returns (address)",
    "function deployCreate3AndInit(bytes,bytes,tuple(uint256,uint256)) payable returns (address)",
    "function deployCreate3AndInit(bytes32,bytes,bytes,tuple(uint256,uint256),address) payable returns (address)",
    "function deployCreate3AndInit(bytes,bytes,tuple(uint256,uint256),address) payable returns (address)",
    "function deployCreateAndInit(bytes,bytes,tuple(uint256,uint256)) payable returns (address)",
    "function deployCreateAndInit(bytes,bytes,tuple(uint256,uint256),address) payable returns (address)",
    "function deployCreateClone(address,bytes) payable returns (address)"
  ];
 // The abi & bytecode will also undergo a hashing check previously and will be imported from a dedicated file
  const Contract = await ethers.getContractFactory(abi, "0x60a06040523060...");
  const contract = await Contract.deploy();
mds1 commented 10 months ago

Right, so to emphasise, these scripts will be amended/refactored once we freeze the code.

Ah this is the key part I was missing. Ok, that all sounds great and this PR LGTM—thanks!