#!/usr/bin/env node
/**
 * Token Discovery Script for ALL Mainnet
 * 
 * Attempts to discover ERC-20 tokens by:
 * 1. Checking recent contract creation events
 * 2. Querying known/common token addresses
 * 3. Scanning for ERC-20 Transfer events
 * 
 * Usage:
 *   node discover-all-mainnet-tokens.js [--recent-blocks=1000] [--check-addresses=0x...,0x...]
 */

import { ethers } from 'ethers';

const RPC_URL = 'https://mainnet-rpc.alltra.global';
const CHAIN_ID = 651940;

// ERC-20 ABI (minimal)
const ERC20_ABI = [
  'function symbol() view returns (string)',
  'function name() view returns (string)',
  'function decimals() view returns (uint8)',
  'function totalSupply() view returns (uint256)'
];

// ERC-20 Transfer event signature
const TRANSFER_EVENT = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';

async function checkToken(address, provider) {
  try {
    const code = await provider.getCode(address);
    if (code === '0x' || code.length < 10) {
      return null;
    }
    
    const contract = new ethers.Contract(address, ERC20_ABI, provider);
    
    const [symbol, name, decimals] = await Promise.all([
      contract.symbol().catch(() => null),
      contract.name().catch(() => null),
      contract.decimals().catch(() => null)
    ]);
    
    if (!symbol || !name || decimals === null) {
      return null;
    }
    
    return {
      chainId: CHAIN_ID,
      address: ethers.getAddress(address),
      name: name,
      symbol: symbol,
      decimals: Number(decimals)
    };
  } catch (error) {
    return null;
  }
}

async function discoverFromRecentBlocks(provider, blockCount = 1000) {
  console.log(`\n🔍 Scanning last ${blockCount} blocks for token contracts...\n`);
  
  const currentBlock = await provider.getBlockNumber();
  const startBlock = Math.max(0, currentBlock - blockCount);
  
  console.log(`Scanning blocks ${startBlock} to ${currentBlock}...`);
  
  // Look for contract creation events
  const tokens = new Set();
  
  // Check recent blocks for contract creations
  for (let i = 0; i < Math.min(100, blockCount); i++) {
    const blockNum = currentBlock - i;
    try {
      const block = await provider.getBlock(blockNum, true);
      if (block && block.transactions) {
        for (const tx of block.transactions) {
          if (tx.to === null && tx.creates) {
            // Contract creation
            tokens.add(tx.creates);
          }
        }
      }
    } catch (error) {
      // Skip errors
    }
  }
  
  console.log(`Found ${tokens.size} potential contract addresses\n`);
  
  const results = [];
  for (const address of tokens) {
    const token = await checkToken(address, provider);
    if (token) {
      results.push(token);
      console.log(`  ✅ ${token.symbol} (${token.name}) - ${token.address}`);
    }
  }
  
  return results;
}

async function checkCommonAddresses(provider) {
  console.log('\n🔍 Checking common token addresses...\n');
  
  // Common stablecoin addresses (may differ on ALL Mainnet)
  const commonAddresses = [
    // USDT-like addresses (these are examples, actual addresses may differ)
    // USDC-like addresses
    // Add more if known
  ];
  
  const results = [];
  
  if (commonAddresses.length === 0) {
    console.log('No common addresses to check. Add addresses to checkCommonAddresses() function.\n');
    return results;
  }
  
  for (const address of commonAddresses) {
    console.log(`Checking ${address}...`);
    const token = await checkToken(address, provider);
    if (token) {
      results.push(token);
      console.log(`  ✅ ${token.symbol} (${token.name})\n`);
    } else {
      console.log(`  ❌ Not a token contract\n`);
    }
  }
  
  return results;
}

async function main() {
  const args = process.argv.slice(2);
  const blockCount = parseInt(args.find(a => a.startsWith('--recent-blocks='))?.split('=')[1] || '1000');
  const checkAddrs = args.find(a => a.startsWith('--check-addresses='))?.split('=')[1]?.split(',') || [];
  
  console.log(`🔍 Discovering tokens on ALL Mainnet (ChainID ${CHAIN_ID})\n`);
  console.log(`RPC: ${RPC_URL}\n`);
  
  const provider = new ethers.JsonRpcProvider(RPC_URL);
  
  // Verify chain
  const network = await provider.getNetwork();
  if (Number(network.chainId) !== CHAIN_ID) {
    console.error(`⚠️  Chain ID mismatch: expected ${CHAIN_ID}, got ${Number(network.chainId)}`);
    process.exit(1);
  }
  
  const currentBlock = await provider.getBlockNumber();
  console.log(`✅ Connected (block: ${currentBlock})\n`);
  
  const allTokens = [];
  
  // Check provided addresses
  if (checkAddrs.length > 0) {
    console.log('🔍 Checking provided addresses...\n');
    for (const addr of checkAddrs) {
      const token = await checkToken(addr, provider);
      if (token) {
        allTokens.push(token);
        console.log(`  ✅ ${token.symbol} (${token.name}) - ${token.address}\n`);
      }
    }
  }
  
  // Check common addresses
  const commonTokens = await checkCommonAddresses(provider);
  allTokens.push(...commonTokens);
  
  // Discover from recent blocks (if requested)
  if (blockCount > 0) {
    const discoveredTokens = await discoverFromRecentBlocks(provider, blockCount);
    allTokens.push(...discoveredTokens);
  }
  
  // Remove duplicates
  const uniqueTokens = Array.from(
    new Map(allTokens.map(t => [t.address.toLowerCase(), t])).values()
  );
  
  if (uniqueTokens.length > 0) {
    console.log(`\n📋 Found ${uniqueTokens.length} token(s):\n`);
    uniqueTokens.forEach((token, i) => {
      console.log(`${i + 1}. ${token.symbol} (${token.name})`);
      console.log(`   Address: ${token.address}`);
      console.log(`   Decimals: ${token.decimals}\n`);
    });
    
    console.log('\n📋 Token List JSON:\n');
    console.log(JSON.stringify({
      tokens: uniqueTokens.map(t => ({
        chainId: t.chainId,
        address: t.address,
        name: t.name,
        symbol: t.symbol,
        decimals: t.decimals
      }))
    }, null, 2));
  } else {
    console.log('\n⚠️  No tokens discovered.\n');
    console.log('To discover tokens:');
    console.log('1. Visit https://alltra.global/tokens');
    console.log('2. Get token addresses from explorer');
    console.log('3. Run: node discover-all-mainnet-tokens.js --check-addresses=0x...,0x...');
  }
}

main().catch(console.error);
