Add complete token lists for Ethereum Mainnet, ChainID 138, and ALL Mainnet

- Added Ethereum Mainnet token list (1 token: USDT)
- Updated ChainID 138 token list (6 tokens: added cUSDT and cUSDC)
- Added ALL Mainnet token list (9 tokens including AUSDT)
- Discovered ALL Mainnet tokens via Transfer event scanning
- Updated validation scripts for multi-chain support
- Created comprehensive documentation and guides
- Updated master documentation indexes
- All token lists validated and ready for submission
This commit is contained in:
defiQUG
2026-01-26 13:52:05 -08:00
parent f5f519a643
commit f0ab0eadc2
32 changed files with 4185 additions and 26 deletions

View File

@@ -0,0 +1,211 @@
#!/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);

View File

@@ -0,0 +1,110 @@
#!/usr/bin/env node
/**
* Token Extraction Helper for ALL Mainnet
*
* This script helps extract token information from ALL Mainnet explorer
* or queries RPC for token metadata.
*
* Usage:
* node extract-tokens-from-explorer.js <token-address> [token-address2 ...]
*/
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)'
];
async function getTokenInfo(address) {
try {
const provider = new ethers.JsonRpcProvider(RPC_URL);
// Verify chain ID
const network = await provider.getNetwork();
if (Number(network.chainId) !== CHAIN_ID) {
console.error(`⚠️ Chain ID mismatch: expected ${CHAIN_ID}, got ${Number(network.chainId)}`);
}
// Check if contract exists
const code = await provider.getCode(address);
if (code === '0x') {
console.error(`❌ No contract code at address ${address}`);
return null;
}
const contract = new ethers.Contract(address, ERC20_ABI, provider);
const [symbol, name, decimals] = await Promise.all([
contract.symbol().catch(() => 'UNKNOWN'),
contract.name().catch(() => 'UNKNOWN'),
contract.decimals().catch(() => 18)
]);
// Checksum address
const checksummedAddress = ethers.getAddress(address);
return {
chainId: CHAIN_ID,
address: checksummedAddress,
name: name,
symbol: symbol,
decimals: Number(decimals),
verified: code !== '0x'
};
} catch (error) {
console.error(`❌ Error querying ${address}:`, error.message);
return null;
}
}
async function main() {
const addresses = process.argv.slice(2);
if (addresses.length === 0) {
console.log('Usage: node extract-tokens-from-explorer.js <token-address> [token-address2 ...]');
console.log('');
console.log('Example:');
console.log(' node extract-tokens-from-explorer.js 0x... 0x...');
console.log('');
console.log('To find token addresses:');
console.log(' 1. Visit https://alltra.global/tokens');
console.log(' 2. Copy token contract addresses');
console.log(' 3. Run this script with the addresses');
process.exit(1);
}
console.log(`🔍 Querying ${addresses.length} token(s) on ALL Mainnet (ChainID ${CHAIN_ID})...\n`);
const results = [];
for (const address of addresses) {
console.log(`Querying ${address}...`);
const info = await getTokenInfo(address);
if (info) {
results.push(info);
console.log(`${info.symbol} (${info.name}) - ${info.decimals} decimals\n`);
}
}
if (results.length > 0) {
console.log('\n📋 Token List JSON:\n');
console.log(JSON.stringify({
tokens: results.map(t => ({
chainId: t.chainId,
address: t.address,
name: t.name,
symbol: t.symbol,
decimals: t.decimals
}))
}, null, 2));
}
}
main().catch(console.error);

View File

@@ -0,0 +1,61 @@
#!/usr/bin/env node
/**
* Find tokens via Transfer events
* ERC-20 tokens emit Transfer events, we can find token addresses this way
*/
import { ethers } from 'ethers';
const RPC_URL = 'https://mainnet-rpc.alltra.global';
const CHAIN_ID = 651940;
// Transfer event signature
const TRANSFER_TOPIC = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
async function findTokensViaEvents() {
const provider = new ethers.JsonRpcProvider(RPC_URL);
console.log(`🔍 Finding tokens via Transfer events on ALL Mainnet (ChainID ${CHAIN_ID})\n`);
const currentBlock = await provider.getBlockNumber();
const fromBlock = Math.max(0, currentBlock - 10000); // Last 10k blocks
console.log(`Scanning blocks ${fromBlock} to ${currentBlock} for Transfer events...\n`);
try {
// Get Transfer events
const filter = {
topics: [TRANSFER_TOPIC],
fromBlock: fromBlock,
toBlock: currentBlock
};
const logs = await provider.getLogs(filter);
console.log(`Found ${logs.length} Transfer events\n`);
// Extract unique contract addresses (token addresses)
const tokenAddresses = new Set();
logs.forEach(log => {
tokenAddresses.add(log.address);
});
console.log(`Found ${tokenAddresses.size} unique token addresses\n`);
console.log('Token addresses found:\n');
const addresses = Array.from(tokenAddresses).slice(0, 20); // Limit to first 20
addresses.forEach((addr, i) => {
console.log(`${i + 1}. ${addr}`);
});
if (addresses.length > 0) {
console.log('\n💡 Use extract-tokens-from-explorer.js to get metadata:');
console.log(`node token-lists/scripts/extract-tokens-from-explorer.js ${addresses.join(' ')}`);
}
} catch (error) {
console.error('Error:', error.message);
console.log('\n💡 Alternative: Visit https://alltra.global/tokens to get token addresses');
}
}
findTokensViaEvents().catch(console.error);

View File

@@ -0,0 +1,42 @@
#!/bin/bash
# Query ALL Mainnet for token information
# This script attempts to query common token addresses on ALL Mainnet
RPC_URL="https://mainnet-rpc.alltra.global"
CHAIN_ID=651940
echo "🔍 Querying ALL Mainnet (ChainID $CHAIN_ID) for token information..."
echo "RPC: $RPC_URL"
echo ""
# Check if cast is available
if ! command -v cast &> /dev/null; then
echo "⚠️ cast (foundry) not available. Install foundry to use this script."
echo " Or use ethers.js/node script instead."
exit 1
fi
# Test RPC connection
echo "Testing RPC connection..."
BLOCK_NUM=$(cast block-number --rpc-url "$RPC_URL" 2>/dev/null)
if [ $? -eq 0 ]; then
echo "✅ RPC accessible (block: $BLOCK_NUM)"
else
echo "❌ RPC not accessible. Cannot query tokens."
exit 1
fi
echo ""
echo "📋 Common token addresses to check:"
echo ""
echo "Note: These are common addresses on other chains. Actual addresses on ALL Mainnet may differ."
echo ""
echo "To find actual tokens:"
echo "1. Visit https://alltra.global/tokens"
echo "2. Check token contract addresses"
echo "3. Query each address for symbol, name, decimals"
echo ""
echo "Example query (replace ADDRESS with actual token address):"
echo " cast call <ADDRESS> 'symbol()(string)' --rpc-url $RPC_URL"
echo " cast call <ADDRESS> 'name()(string)' --rpc-url $RPC_URL"
echo " cast call <ADDRESS> 'decimals()(uint8)' --rpc-url $RPC_URL"

39
token-lists/scripts/types.d.ts vendored Normal file
View File

@@ -0,0 +1,39 @@
/**
* TypeScript type definitions for token list validation
* Re-exports types from @uniswap/token-lists for use in validation scripts
*
* This file provides type definitions that can be used with JSDoc comments
* in JavaScript files or imported in TypeScript files.
*/
/**
* @typedef {import('@uniswap/token-lists').TokenList} TokenList
* @typedef {import('@uniswap/token-lists').TokenInfo} TokenInfo
* @typedef {import('@uniswap/token-lists').Version} Version
* @typedef {import('@uniswap/token-lists').Tags} Tags
*/
// Re-export types from @uniswap/token-lists for convenience
export type {
TokenList,
TokenInfo,
Version,
Tags
} from '@uniswap/token-lists';
/**
* Validation result type
*/
export interface ValidationResult {
valid: boolean;
errors: string[];
warnings: string[];
}
/**
* On-chain verification result
*/
export interface VerificationResult {
type: 'success' | 'warning' | 'error';
message: string;
}

View File

@@ -3,7 +3,7 @@
* Enhanced Token List Validator
* Validates token lists against the Uniswap Token Lists JSON schema
* Based on: https://github.com/Uniswap/token-lists
* Schema: https://uniswap.org/tokenlist.schema.json
* Uses: @uniswap/token-lists package for schema and types
*
* Enhanced with:
* - EIP-55 checksum validation
@@ -21,14 +21,29 @@ import { ethers } from 'ethers';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Required chain ID
const REQUIRED_CHAIN_ID = 138;
// Required chain ID (optional - if not set, will validate all tokens have same chainId)
// Can be overridden via --chain-id flag
let REQUIRED_CHAIN_ID = null;
// Fetch schema from Uniswap
const SCHEMA_URL = 'https://uniswap.org/tokenlist.schema.json';
async function fetchSchema() {
/**
* Get schema from @uniswap/token-lists package
* Falls back to fetching from URL if package not available
*/
async function getSchema() {
try {
// Try to import schema from @uniswap/token-lists package
const tokenLists = await import('@uniswap/token-lists');
if (tokenLists.schema) {
console.log('✅ Using schema from @uniswap/token-lists package\n');
return tokenLists.schema;
}
} catch (error) {
console.log('⚠️ @uniswap/token-lists package not available, fetching schema from URL...\n');
}
// Fallback: fetch schema from Uniswap
try {
const SCHEMA_URL = 'https://uniswap.org/tokenlist.schema.json';
const response = await fetch(SCHEMA_URL);
if (!response.ok) {
throw new Error(`Failed to fetch schema: ${response.statusText}`);
@@ -56,6 +71,7 @@ function enhancedValidation(tokenList) {
const warnings = [];
const seenAddresses = new Set();
const seenSymbols = new Map(); // chainId -> Set of symbols
let detectedChainId = null;
// Required fields
if (!tokenList.name || typeof tokenList.name !== 'string') {
@@ -81,6 +97,11 @@ function enhancedValidation(tokenList) {
return { errors, warnings, valid: false };
}
// Detect chain ID from first token if not specified
if (tokenList.tokens.length > 0 && tokenList.tokens[0].chainId) {
detectedChainId = tokenList.tokens[0].chainId;
}
// Validate each token
tokenList.tokens.forEach((token, index) => {
const prefix = `Token[${index}]`;
@@ -89,8 +110,15 @@ function enhancedValidation(tokenList) {
if (typeof token.chainId !== 'number') {
errors.push(`${prefix}: Missing or invalid "chainId"`);
} else {
// Strict chain ID validation
if (token.chainId !== REQUIRED_CHAIN_ID) {
// Chain ID consistency check
if (detectedChainId === null) {
detectedChainId = token.chainId;
} else if (token.chainId !== detectedChainId) {
errors.push(`${prefix}: chainId mismatch - expected ${detectedChainId}, got ${token.chainId}`);
}
// Strict chain ID validation (if REQUIRED_CHAIN_ID is set)
if (REQUIRED_CHAIN_ID !== null && token.chainId !== REQUIRED_CHAIN_ID) {
errors.push(`${prefix}: chainId must be ${REQUIRED_CHAIN_ID}, got ${token.chainId}`);
}
}
@@ -170,8 +198,8 @@ async function validateTokenList(filePath) {
process.exit(1);
}
// Try to fetch and use Uniswap schema
const schema = await fetchSchema();
// Get schema from @uniswap/token-lists package or fetch from URL
const schema = await getSchema();
let validationResult;
if (schema) {
@@ -273,10 +301,16 @@ async function validateTokenList(filePath) {
}
// Main
const filePath = process.argv[2] || resolve(__dirname, '../lists/dbis-138.tokenlist.json');
const args = process.argv.slice(2);
const filePath = args.find(arg => !arg.startsWith('--')) || resolve(__dirname, '../lists/dbis-138.tokenlist.json');
const chainIdArg = args.find(arg => arg.startsWith('--chain-id='));
if (chainIdArg) {
REQUIRED_CHAIN_ID = parseInt(chainIdArg.split('=')[1], 10);
}
if (!filePath) {
console.error('Usage: node validate-token-list.js [path/to/token-list.json]');
console.error('Usage: node validate-token-list.js [path/to/token-list.json] [--chain-id=138]');
process.exit(1);
}