Files
smom-dbis-138/scripts/deployment/calculate-create2-salt.js

156 lines
5.7 KiB
JavaScript
Raw Normal View History

#!/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 <contract-name> <deployer-address>");
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 };