Files
proxmox/token-lists/scripts/discover-all-mainnet-tokens.js

212 lines
6.2 KiB
JavaScript
Raw Normal View History

#!/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);