#!/usr/bin/env node
/**
 * Verify WETH9_138 fingerprint (symbol, name, decimals, optional bytecode hash).
 * Bot/executor must run at startup and halt if fingerprint does not match expected.
 * Usage: node verify-weth9-fingerprint.js [--no-exit]
 * Exit 0 = match, 1 = mismatch or error.
 */
const WETH9_ADDRESS = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const RPC_138 = process.env.RPC_URL_138 || 'https://rpc-http-pub.d-bis.org';
const RPC_MAINNET = process.env.ETHEREUM_MAINNET_RPC || 'https://eth.llamarpc.com';

const SELECTORS = { symbol: '0x95d89b41', name: '0x06fdde03', decimals: '0x313ce567' };

async function call(rpcUrl, to, data) {
  const res = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_call', params: [{ to, data }, 'latest'], id: 1 }),
  });
  const d = await res.json();
  if (d.error) throw new Error(d.error.message || JSON.stringify(d.error));
  return d.result;
}

async function getCode(rpcUrl, address) {
  const res = await fetch(rpcUrl, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ jsonrpc: '2.0', method: 'eth_getCode', params: [address, 'latest'], id: 1 }),
  });
  const d = await res.json();
  if (d.error) throw new Error(d.error.message || JSON.stringify(d.error));
  return d.result;
}

function decodeString(hex) {
  if (!hex || hex === '0x') return '';
  try {
    const ethers = require('ethers');
    return ethers.AbiCoder.defaultAbiCoder().decode(['string'], hex)[0];
  } catch (_) { return hex; }
}

function decodeUint8(hex) {
  if (!hex || hex === '0x') return 0;
  return parseInt(hex.slice(-2), 16);
}

async function getFingerprint(rpcUrl, address) {
  const [symbolHex, nameHex, decimalsHex] = await Promise.all([
    call(rpcUrl, address, SELECTORS.symbol),
    call(rpcUrl, address, SELECTORS.name),
    call(rpcUrl, address, SELECTORS.decimals),
  ]);
  const ethers = require('ethers');
  const code = await getCode(rpcUrl, address);
  const codeHash = code && code !== '0x' ? ethers.keccak256(code) : null;
  return {
    symbol: decodeString(symbolHex),
    name: decodeString(nameHex),
    decimals: decodeUint8(decimalsHex),
    codeHash,
  };
}

async function main() {
  const fp138 = await getFingerprint(RPC_138, WETH9_ADDRESS);
  console.log('Chain 138 fingerprint:', JSON.stringify(fp138, null, 2));
  const fpMain = await getFingerprint(RPC_MAINNET, WETH9_ADDRESS);
  console.log('Ethereum mainnet fingerprint:', JSON.stringify(fpMain, null, 2));
  const match = fp138.symbol === fpMain.symbol && fp138.name === fpMain.name
    && fp138.decimals === fpMain.decimals
    && (fp138.codeHash == null || fpMain.codeHash == null || fp138.codeHash === fpMain.codeHash);
  if (match) {
    console.log('Match: YES — WETH9_138 fingerprint matches expected.');
    process.exit(0);
  }
  console.error('Halt: WETH9_138 fingerprint mismatch.');
  process.exit(1);
}

main().catch((err) => { console.error(err); process.exit(1); });
