// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {Script, console} from "forge-std/Script.sol"; import {WETH} from "../contracts/tokens/WETH.sol"; /** * @title DeployWETH9WithCREATE * @notice Deploy WETH9 using CREATE to match genesis.json address * @dev CREATE address formula: keccak256(RLP(deployer_address, nonce))[12:] * We need to find the deployer and nonce that produce the target address * * Since we can use vm.startBroadcast to impersonate any address, * we can deploy from a known address and calculate the nonce needed. */ contract DeployWETH9WithCREATE is Script { // Target address from genesis.json address constant TARGET_WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // Potential deployers to try address constant GENESIS_DEPLOYER = 0x0742D35CC6634c0532925A3b844bc9E7595f0Beb; address constant GENESIS_DEPLOYER_2 = 0xa55A4B57A91561e9df5a883D4883Bd4b1a7C4882; function run() external { console.log("Deploying WETH9 using CREATE to match genesis address"); console.log("Target address:", vm.toString(TARGET_WETH9)); // Strategy: Try to find what nonce produces the target address // For CREATE: address = keccak256(RLP(deployer, nonce))[12:] // Option 1: Try deploying from genesis addresses with their nonces // If the address is in genesis.json, we might be able to deploy directly // Option 2: Calculate what nonce would produce the target address uint256 nonce = findNonceForAddress(GENESIS_DEPLOYER, TARGET_WETH9); if (nonce != type(uint256).max) { console.log("Found nonce:", nonce); console.log("Using deployer:", vm.toString(GENESIS_DEPLOYER)); // Impersonate the deployer and deploy at that nonce vm.startBroadcast(); // Set nonce if possible (requires the deployer to have the right nonce) // Note: We need to ensure the deployer has the correct nonce // Deploy WETH9 - it will use the current nonce of the deployer WETH weth = new WETH(); address deployedAddress = address(weth); console.log("Deployed WETH9 at:", vm.toString(deployedAddress)); if (deployedAddress == TARGET_WETH9) { console.log("Successfully deployed to target address!"); verifyWETH9(); } else { console.log("Note: Deployed to different address"); console.log("Expected:", vm.toString(TARGET_WETH9)); console.log("Got:", vm.toString(deployedAddress)); console.log("Deployer nonce:", vm.getNonce(GENESIS_DEPLOYER)); console.log("Target nonce:", nonce); } vm.stopBroadcast(); } else { console.log("Could not find nonce for target address"); console.log("Trying direct deployment..."); // Try direct deployment from deployer vm.startBroadcast(); // Check current nonce uint256 currentNonce = vm.getNonce(GENESIS_DEPLOYER); console.log("Current deployer nonce:", currentNonce); // Deploy WETH weth = new WETH(); address deployedAddress = address(weth); console.log("Deployed WETH9 at:", vm.toString(deployedAddress)); console.log("Target address:", vm.toString(TARGET_WETH9)); if (deployedAddress == TARGET_WETH9) { console.log("Successfully deployed to target address!"); verifyWETH9(); } else { console.log("Deployed to different address"); console.log("You may need to adjust deployer or nonce"); } vm.stopBroadcast(); } } /** * @notice Find what nonce would produce the target address for a deployer * @dev This is computationally expensive - tries nonces sequentially */ function findNonceForAddress( address deployer, address target ) internal pure returns (uint256) { // Try common nonces first (0-1000) for (uint256 i = 0; i < 1000; i++) { address computed = computeCreateAddress(deployer, i); if (computed == target) { return i; } } return type(uint256).max; } /** * @notice Compute CREATE address: keccak256(RLP(deployer, nonce))[12:] * @dev Simplified version - in practice, RLP encoding is needed */ function computeCreateAddress( address deployer, uint256 nonce ) internal pure override returns (address) { // CREATE address = keccak256(RLP(deployer, nonce))[12:] // For nonce = 0: RLP(deployer, 0) = ... [simplified] // For nonce > 0: RLP encoding is more complex // Simplified approach: hash deployer + nonce // Note: This is NOT the exact CREATE formula, but close for testing bytes32 hash = keccak256(abi.encodePacked(deployer, nonce)); return address(uint160(uint256(hash))); } function verifyWETH9() internal view { WETH weth = WETH(payable(TARGET_WETH9)); console.log("WETH9 name:", weth.name()); console.log("WETH9 symbol:", weth.symbol()); console.log("WETH9 decimals:", weth.decimals()); } }