#!/usr/bin/env node

/**
 * Calculate CREATE address given deployer and nonce
 * 
 * CREATE formula:
 * address = keccak256(RLP(deployer_address, nonce))[12:]
 * 
 * RLP encoding:
 * - For nonce = 0: RLP([deployer_address]) 
 * - For nonce > 0: RLP([deployer_address, nonce])
 */

const { ethers } = require("ethers");
const RLP = require("rlp");

// Target addresses from genesis.json
const TARGET_WETH9 = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2";
const TARGET_WETH10 = "0xf4BB2e28688e89fCcE3c0580D37d36A7672E8A9F";

// Potential deployers
const DEPLOYERS = [
    "0x0742D35CC6634c0532925A3b844bc9E7595f0Beb",
    "0xa55A4B57A91561e9df5a883D4883Bd4b1a7C4882",
    "0x4a666f96fc8764181194447a7dfdb7d471b301c8",
];

/**
 * Calculate CREATE address using RLP encoding
 */
function calculateCreateAddress(deployer, nonce) {
    const deployerBytes = Buffer.from(deployer.slice(2), 'hex');
    
    let rlpEncoded;
    if (nonce === 0) {
        // RLP([deployer_address])
        rlpEncoded = RLP.encode([deployerBytes]);
    } else {
        // RLP([deployer_address, nonce])
        const nonceHex = nonce.toString(16);
        const nonceBytes = Buffer.from(nonceHex.padStart(nonceHex.length + (nonceHex.length % 2), '0'), 'hex');
        rlpEncoded = RLP.encode([deployerBytes, nonceBytes]);
    }
    
    const hash = ethers.keccak256(rlpEncoded);
    const address = '0x' + hash.slice(-40);
    return ethers.getAddress(address);
}

/**
 * Find nonce that produces target address
 */
function findNonceForTarget(targetAddress, deployer, maxNonce = 10000) {
    console.log(`Finding nonce for deployer ${deployer} to produce ${targetAddress}...`);
    
    for (let nonce = 0; nonce < maxNonce; nonce++) {
        const computed = calculateCreateAddress(deployer, nonce);
        
        if (nonce % 1000 === 0 && nonce > 0) {
            process.stdout.write(`\rChecked ${nonce} nonces...`);
        }
        
        if (computed.toLowerCase() === targetAddress.toLowerCase()) {
            console.log(`\n✅ Found nonce: ${nonce}`);
            console.log(`   Deployer: ${deployer}`);
            console.log(`   Computed: ${computed}`);
            return nonce;
        }
    }
    
    console.log(`\n❌ Could not find nonce after ${maxNonce} attempts`);
    return null;
}

async function main() {
    const args = process.argv.slice(2);
    
    if (args.length < 1) {
        console.log("Usage: node calculate-create-address.js <target-address> [deployer-address] [max-nonce]");
        console.log("");
        console.log("Examples:");
        console.log("  node calculate-create-address.js 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2");
        console.log("  node calculate-create-address.js 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 0x0742D35CC6634c0532925A3b844bc9E7595f0Beb");
        process.exit(1);
    }
    
    const targetAddress = ethers.getAddress(args[0]);
    const deployer = args[1] ? ethers.getAddress(args[1]) : DEPLOYERS[0];
    const maxNonce = args[2] ? parseInt(args[2]) : 10000;
    
    console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    console.log("Calculate CREATE Address");
    console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
    console.log("");
    console.log(`Target Address: ${targetAddress}`);
    console.log(`Deployer: ${deployer}`);
    console.log(`Max Nonce: ${maxNonce}`);
    console.log("");
    
    // Try all deployers if not specified
    const deployersToTry = args[1] ? [deployer] : DEPLOYERS;
    
    for (const deployerAddr of deployersToTry) {
        const nonce = findNonceForTarget(targetAddress, deployerAddr, maxNonce);
        
        if (nonce !== null) {
            console.log("");
            console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            console.log("✅ CREATE Parameters Found");
            console.log("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
            console.log(`Target Address: ${targetAddress}`);
            console.log(`Deployer: ${deployerAddr}`);
            console.log(`Nonce: ${nonce}`);
            console.log("");
            console.log("Use these parameters in your deployment script:");
            console.log(`  vm.startBroadcast(${deployerAddr});`);
            console.log(`  // Ensure nonce is ${nonce}`);
            console.log(`  WETH weth = new WETH();`);
            console.log("");
            process.exit(0);
        }
    }
    
    console.log("");
    console.log("❌ Could not find CREATE parameters for any deployer");
    console.log("You may need to:");
    console.log("  1. Try different deployers");
    console.log("  2. Increase max-nonce");
    console.log("  3. Check if address was deployed with different method");
    process.exit(1);
}

if (require.main === module) {
    main().catch(console.error);
}

module.exports = { calculateCreateAddress, findNonceForTarget };

