#!/usr/bin/env node /** * Calculate CREATE2 salt to produce a specific contract address * * CREATE2 formula: * address = keccak256(0xff ++ deployer ++ salt ++ keccak256(bytecode))[12:] */ const { ethers } = require("ethers"); const fs = require("fs"); const path = require("path"); // Target addresses from genesis.json const TARGET_WETH9 = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; const TARGET_WETH10 = "0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F"; // Load contract bytecode from artifacts function loadBytecode(contractName) { const artifactsPath = path.join(__dirname, "../../out", contractName, `${contractName}.sol`, `${contractName}.json`); if (!fs.existsSync(artifactsPath)) { throw new Error(`Artifact not found: ${artifactsPath}`); } const artifact = JSON.parse(fs.readFileSync(artifactsPath, "utf8")); return artifact.bytecode.object; } // Calculate CREATE2 address function calculateCreate2Address(deployer, salt, bytecode) { const bytecodeHash = ethers.keccak256(bytecode); const initCodeHash = ethers.keccak256( ethers.concat([ "0xff", deployer, salt, bytecodeHash, ]) ); return ethers.getAddress("0x" + initCodeHash.slice(26)); } // Find salt that produces target address function findSalt(deployer, bytecode, targetAddress, maxIterations = 1000000) { console.log(`Finding salt for target address: ${targetAddress}`); console.log(`Deployer: ${deployer}`); console.log(`Bytecode length: ${bytecode.length} bytes`); console.log(`Max iterations: ${maxIterations}`); console.log(""); // Try common salts first const commonSalts = [ "0x0000000000000000000000000000000000000000000000000000000000000000", // Zero "0x0000000000000000000000000000000000000000000000000000000000000001", // One "0x000000000000000000000000000000000000000000000000000000000000008a", // Chain ID 138 ethers.keccak256(ethers.toUtf8Bytes("WETH9")), ethers.keccak256(ethers.toUtf8Bytes("WETH10")), ethers.keccak256(ethers.toUtf8Bytes("WETH")), ethers.keccak256(ethers.toUtf8Bytes("Wrapped Ether")), ethers.keccak256(ethers.toUtf8Bytes("ChainID-138-WETH9")), ethers.keccak256(ethers.toUtf8Bytes("ChainID-138-WETH10")), ]; console.log("Trying common salts..."); for (const salt of commonSalts) { const address = calculateCreate2Address(deployer, salt, bytecode); console.log(` Salt: ${salt.slice(0, 20)}... → Address: ${address}`); if (address.toLowerCase() === targetAddress.toLowerCase()) { console.log(`\n✅ Found salt: ${salt}`); return salt; } } console.log("\nCommon salts didn't match. Brute forcing..."); console.log("(This may take a while)"); // Brute force for (let i = 0; i < maxIterations; i++) { const salt = ethers.zeroPadValue(ethers.toBeHex(i, 32), 32); const address = calculateCreate2Address(deployer, salt, bytecode); if (i % 10000 === 0) { process.stdout.write(`\rChecked ${i} salts...`); } if (address.toLowerCase() === targetAddress.toLowerCase()) { console.log(`\n✅ Found salt: ${salt} (iteration ${i})`); return salt; } } console.log(`\n❌ Could not find salt after ${maxIterations} iterations`); return null; } async function main() { const args = process.argv.slice(2); if (args.length < 2) { console.log("Usage: node calculate-create2-salt.js "); console.log(""); console.log("Examples:"); console.log(" node calculate-create2-salt.js WETH 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"); console.log(" node calculate-create2-salt.js WETH10 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"); process.exit(1); } const contractName = args[0]; const deployer = ethers.getAddress(args[1]); let targetAddress; if (contractName === "WETH" || contractName === "WETH9") { targetAddress = TARGET_WETH9; } else if (contractName === "WETH10") { targetAddress = TARGET_WETH10; } else { console.error(`Unknown contract: ${contractName}`); process.exit(1); } try { const bytecode = loadBytecode(contractName); const salt = findSalt(deployer, bytecode, targetAddress); if (salt) { console.log(""); console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); console.log("✅ CREATE2 Salt Found"); console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); console.log(`Contract: ${contractName}`); console.log(`Target Address: ${targetAddress}`); console.log(`Deployer: ${deployer}`); console.log(`Salt: ${salt}`); console.log(""); console.log("Use this salt in your CREATE2 deployment script!"); } else { console.log(""); console.log("❌ Could not find salt"); console.log("You may need to:"); console.log(" 1. Increase maxIterations"); console.log(" 2. Check if bytecode matches"); console.log(" 3. Verify deployer address"); process.exit(1); } } catch (error) { console.error(`Error: ${error.message}`); process.exit(1); } } if (require.main === module) { main().catch(console.error); } module.exports = { calculateCreate2Address, findSalt };