From: Ardis Lu Date: Sat, 17 Jun 2023 06:59:18 +0000 (-0700) Subject: Initial commit X-Git-Url: https://git.ardis.lu/?a=commitdiff_plain;h=23b4de8e319ec46d9498b737fa97dd82d2e4783d;p=minimal-create2 Initial commit --- 23b4de8e319ec46d9498b737fa97dd82d2e4783d diff --git a/README.md b/README.md new file mode 100644 index 0000000..38c049d --- /dev/null +++ b/README.md @@ -0,0 +1,88 @@ +# minimal-create2 + +This is the minimal amount of code required to mine a smart contract address using `CREATE2`. + +## Create the `CREATE2` deployment factory + +Create a new smart contract with the minimum amount of code required to call `CREATE2` by pasting this code into DevTools (assuming Metamask is installed): + +```javascript +await ethereum.request({ + method: 'eth_sendTransaction', + params: [{ + from: (await ethereum.request({ method: 'eth_requestAccounts' }))[0], // Your currently active MetaMask address + data: '0x6d365f5f375f516020360360205ff55f52600e6012f3' // create2-deployment.evm, compiled + }] +}); +``` + +`create2-deployment.evm` contains bytecode that deploys `create2.evm`. `create2.evm` is a minimal smart contract written in EVM assembly which expects a 32-byte salt and arbitrary bytecode in its calldata and deploys the bytecode using the `CREATE2` opcode. + +**Important**: If you want the same `CREATE2` contract address *across chains*, you should use a fresh EOA with no prior transactions to create this deployment factory. Otherwise, the deployment factories will have different addresses and will output different `CREATE2` addresses. + +## Mine the desired `CREATE2` address + +Simple example of predicting the `CREATE2` address: + +```javascript +const ethers = await import('https://cdn.jsdelivr.net/npm/ethers@6.6.0/+esm'); + +// The smart contract you deployed in "Create the CREATE2 deployment factory" +const factory = '0x8137a81A74E2a9d510898B2e3E307e7C33eBad8A'; + +// Salt must be hex and exactly 32 bytes +const salt = '0x0000000000000000000000000000000000000000000000000000000000000123'; + +// Must be the entire creation bytecode, including constructor arguments +const bytecode = '0x385f818153f3'; // minimal-contract-deployment.evm, compiled + +ethers.getCreate2Address(factory, salt, ethers.keccak256(bytecode)); +// 0xD7ada5e4De61a3c14994046d349d90F7ae693433 +``` + +Example of mining a specific smart contract address by testing different `salt` values: + +```javascript +const ethers = await import('https://cdn.jsdelivr.net/npm/ethers@6.6.0/+esm'); + +// The smart contract you deployed in "Create the CREATE2 deployment factory" +const factory = '0x8137a81A74E2a9d510898B2e3E307e7C33eBad8A'; + +// Must be the entire creation bytecode, including constructor arguments +const bytecode = '0x385f818153f3'; // minimal-contract-deployment.evm, compiled + +const requirement = /^0xbeef/; + +let salt = 1; +while (true) { + const paddedSalt = `0x${salt.toString(16).padStart(64, '0')}`; + const addr = ethers.getCreate2Address(factory, paddedSalt, ethers.keccak256(bytecode)); + if (requirement.test(addr)) { + console.log({factory, paddedSalt, bytecode, addr}); + break; + } + salt++; +} +// {factory: '0x8137a81A74E2a9d510898B2e3E307e7C33eBad8A', paddedSalt: '0x000000000000000000000000000000000000000000000000000000000005c342', bytecode: '0x385f818153f3', addr: '0xbeef7906063D950306868AF5af36955015110f84'} +``` + +## Using the mined `salt` + +Once a desired `CREATE2` address has been mined, you can deploy it by sending the mined `salt` parameter to the smart contract deployed in "Create the `CREATE2` deployment factory". + +```javascript +// Same parameters from "Mine the desired CREATE2 address" +const factory = '8137a81A74E2a9d510898B2e3E307e7C33eBad8A'; // Drop "0x" prefix +const salt = '000000000000000000000000000000000000000000000000000000000005c342'; // Drop "0x" prefix +const bytecode = '385f818153f3'; // Drop "0x" prefix + +await ethereum.request({ + method: 'eth_sendTransaction', + params: [{ + from: (await ethereum.request({ method: 'eth_requestAccounts' }))[0], // Your currently active MetaMask address + to: `0x${factory}`, + data: `0x${salt}${bytecode}` + }] +}); +// Smart contract is deployed as 0xbeef7906063D950306868AF5af36955015110f84, as predicted +``` diff --git a/create2-deployment.evm b/create2-deployment.evm new file mode 100644 index 0000000..7f76902 --- /dev/null +++ b/create2-deployment.evm @@ -0,0 +1,12 @@ +;; Store create2.evm compiled bytecode into memory +PUSH 0x365f5f375f516020360360205ff5 +PUSH0 +MSTORE + +;; Return create2.evm compiled bytecode +PUSH 14 +PUSH 18 +RETURN + +;; This contract, compiled: +;; 6d365f5f375f516020360360205ff55f52600e6012f3 diff --git a/create2.evm b/create2.evm new file mode 100644 index 0000000..a768e8e --- /dev/null +++ b/create2.evm @@ -0,0 +1,23 @@ +;; Copy calldata to memory offset 0 +CALLDATASIZE +PUSH0 +PUSH0 +CALLDATACOPY + + +;; First 32 bytes of calldata is the salt +PUSH0 +MLOAD + +;; Remaining calldata is the creation bytecode +PUSH 32 +CALLDATASIZE +SUB + +;; Call CREATE2 +PUSH 32 +PUSH0 +CREATE2 + +;; This contract, compiled: +;; 365f5f375f516020360360205ff5 diff --git a/minimal-contract-deployment.evm b/minimal-contract-deployment.evm new file mode 100644 index 0000000..f01dc05 --- /dev/null +++ b/minimal-contract-deployment.evm @@ -0,0 +1,13 @@ +;; This is the minimal bytecode that can be used to deploy a new smart contract +CODESIZE +PUSH0 +DUP2 +DUP2 +MSTORE8 +RETURN + +;; This smart contract, compiled: +;; 385f818153f3 + +;; When sent to EVM, this smart contract will deploy a new smart contract with bytecode: +;; 060000000000