Files
smom-dbis-138/script/DeployWETH9ToExactAddress.s.sol

249 lines
10 KiB
Solidity
Raw Permalink Normal View History

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Script, console} from "forge-std/Script.sol";
import {WETH} from "../contracts/tokens/WETH.sol";
import {CREATE2Factory} from "../contracts/utils/CREATE2Factory.sol";
/**
* @title DeployWETH9ToExactAddress
* @notice Deploy WETH9 to exact address 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 using CREATE2
* @dev This script uses CREATE2 to deploy to the exact address specified in genesis.json
*/
contract DeployWETH9ToExactAddress is Script {
// Target address from genesis.json
address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address deployer = vm.addr(deployerPrivateKey);
console.log("Deploying WETH9 to exact address using CREATE2");
console.log("Target address:", vm.toString(TARGET_WETH9));
console.log("Deployer:", vm.toString(deployer));
vm.startBroadcast(deployerPrivateKey);
// Get WETH bytecode
bytes memory wethBytecode = type(WETH).creationCode;
bytes32 bytecodeHash = keccak256(wethBytecode);
console.log("WETH bytecode hash:", vm.toString(bytecodeHash));
// Deploy CREATE2Factory (or use existing if already deployed)
// For deterministic deployment, we can use a known CREATE2Factory address
// or deploy it first and use that address
CREATE2Factory factory = new CREATE2Factory();
address factoryAddress = address(factory);
console.log("CREATE2Factory deployed at:", factoryAddress);
// Calculate salt that produces the target address
// CREATE2 formula: keccak256(0xff ++ deployer ++ salt ++ keccak256(bytecode))
// We need to find salt such that the result is TARGET_WETH9
// Try common salts or calculate one that works
// For now, we'll use a salt finder approach
// Since finding the exact salt requires brute force, we'll use a known salt
// that produces the target address when combined with our factory
// Check if contract already exists on-chain
// Note: We'll try to interact with it - if it reverts, it doesn't exist
try this.checkContractExists(TARGET_WETH9) returns (bool exists) {
if (exists) {
console.log("Contract already exists at target address");
WETH weth = WETH(payable(TARGET_WETH9));
console.log("WETH9 name:", weth.name());
console.log("WETH9 symbol:", weth.symbol());
vm.stopBroadcast();
return;
}
} catch {
// Contract doesn't exist, continue with deployment
}
// Try multiple deployer addresses:
// 1. Current deployer
// 2. CREATE2Factory address (as deployer)
// 3. Standard CREATE2 deterministic deployer
// 4. Addresses from genesis.json
address[] memory deployers = new address[](5);
deployers[0] = deployer;
deployers[1] = factoryAddress;
deployers[2] = 0x4e59b44847b379578588920cA78FbF26c0B4956C; // Standard CREATE2 deployer
deployers[3] = 0x0742D35CC6634c0532925A3b844bc9E7595f0Beb; // Genesis address with initial balance (padded)
deployers[4] = 0xa55A4B57A91561e9df5a883D4883Bd4b1a7C4882; // Genesis address with high balance
uint256 salt = 0;
address foundDeployer = address(0);
for (uint256 i = 0; i < deployers.length; i++) {
console.log("Trying deployer:", vm.toString(deployers[i]));
// Try common salts first
salt = findSaltForAddress(deployers[i], wethBytecode, TARGET_WETH9);
if (salt != 0) {
foundDeployer = deployers[i];
console.log("Found salt with common salts!");
break;
}
// Try brute force
console.log("Brute forcing salt (this may take a while)...");
salt = bruteForceSalt(deployers[i], wethBytecode, TARGET_WETH9);
if (salt != 0) {
foundDeployer = deployers[i];
console.log("Found salt via brute force!");
break;
}
}
if (salt != 0 && foundDeployer != address(0)) {
console.log("Found salt:", vm.toString(salt));
console.log("Using deployer:", vm.toString(foundDeployer));
// If the found deployer is the factory, use it
if (foundDeployer == factoryAddress) {
// Verify address calculation
address predictedAddress = CREATE2Factory(factoryAddress).computeAddress(wethBytecode, salt);
console.log("Predicted address:", vm.toString(predictedAddress));
if (predictedAddress == TARGET_WETH9) {
// Deploy using CREATE2Factory
address wethAddress = factory.deploy(wethBytecode, salt);
console.log("WETH9 deployed at:", wethAddress);
require(wethAddress == TARGET_WETH9, "Address mismatch");
// Verify deployment
WETH weth = WETH(payable(wethAddress));
console.log("WETH9 name:", weth.name());
console.log("WETH9 symbol:", weth.symbol());
console.log("WETH9 decimals:", weth.decimals());
} else {
revert("Predicted address does not match target");
}
} else {
// Need to deploy using the found deployer address directly
// This requires deploying via that address or using a CREATE2 helper
console.log("Deployer address found, but not using factory.");
console.log("You may need to deploy using the deployer address:", vm.toString(foundDeployer));
console.log("Salt:", vm.toString(salt));
revert("Deployer is not the factory - manual deployment may be required");
}
} else {
revert("Could not find salt and deployer combination to produce target address");
}
vm.stopBroadcast();
console.log("\n=== Deployment Summary ===");
console.log("WETH9 Address:", vm.toString(TARGET_WETH9));
console.log("CREATE2Factory:", vm.toString(factoryAddress));
console.log("Salt:", vm.toString(salt));
}
function findSaltForAddress(
address deployerAddr,
bytes memory bytecode,
address targetAddr
) internal pure returns (uint256) {
// Try common salts
bytes32 bytecodeHash = keccak256(bytecode);
bytes32[] memory commonSalts = new bytes32[](10);
commonSalts[0] = keccak256("WETH9");
commonSalts[1] = keccak256("WETH");
commonSalts[2] = keccak256("Wrapped Ether");
commonSalts[3] = keccak256("ChainID-138-WETH9");
commonSalts[4] = keccak256(abi.encodePacked("WETH9", uint256(138)));
commonSalts[5] = bytes32(uint256(0)); // Zero salt
commonSalts[6] = bytes32(uint256(1)); // Salt of 1
commonSalts[7] = bytes32(uint256(138)); // Chain ID
commonSalts[8] = keccak256(abi.encodePacked(targetAddr));
commonSalts[9] = bytes32(uint256(uint160(targetAddr)));
for (uint i = 0; i < commonSalts.length; i++) {
bytes32 hash = keccak256(
abi.encodePacked(bytes1(0xff), deployerAddr, commonSalts[i], bytecodeHash)
);
address computedAddr = address(uint160(uint256(hash)));
if (computedAddr == targetAddr) {
return uint256(commonSalts[i]);
}
}
return 0;
}
function bruteForceSalt(
address deployerAddr,
bytes memory bytecode,
address targetAddr
) internal pure returns (uint256) {
// Enhanced brute force: checks more values and different salt patterns
bytes32 bytecodeHash = keccak256(bytecode);
// Try sequential salts first (0 to 10,000)
for (uint256 i = 0; i < 10000; i++) {
bytes32 salt = bytes32(i);
bytes32 hash = keccak256(
abi.encodePacked(bytes1(0xff), deployerAddr, salt, bytecodeHash)
);
address computedAddr = address(uint160(uint256(hash)));
if (computedAddr == targetAddr) {
return uint256(salt);
}
}
// Try powers of 2 and common values
uint256[] memory commonValues = new uint256[](20);
commonValues[0] = 138; // Chain ID
commonValues[1] = 1;
commonValues[2] = 2;
commonValues[3] = 10;
commonValues[4] = 100;
commonValues[5] = 1000;
commonValues[6] = 10000;
commonValues[7] = 100000;
commonValues[8] = type(uint128).max;
commonValues[9] = type(uint256).max;
for (uint256 j = 10; j < 20; j++) {
commonValues[j] = uint256(keccak256(abi.encodePacked("WETH9", j)));
}
for (uint256 k = 0; k < commonValues.length; k++) {
bytes32 salt = bytes32(commonValues[k]);
bytes32 hash = keccak256(
abi.encodePacked(bytes1(0xff), deployerAddr, salt, bytecodeHash)
);
address computedAddr = address(uint160(uint256(hash)));
if (computedAddr == targetAddr) {
return uint256(salt);
}
}
return 0;
}
function deployDirectlyWithCreate2(
address deployer,
bytes memory bytecode,
address targetAddr
) internal returns (address) {
// This function would deploy directly using CREATE2 opcode
// For now, we'll revert if we can't find the right salt
revert("Direct CREATE2 deployment not implemented - salt finding required");
}
// Helper function to check if contract exists
function checkContractExists(address addr) external view returns (bool) {
uint256 size;
assembly {
size := extcodesize(addr)
}
return size > 0;
}
}