Kaspa L2查询合约余额代码
const Web3 = require('web3');
const readline = require('readline-sync');
// 连接到 EVM 网络
const rpcUrl = 'https://evmrpc.kasplex.org';
const web3 = new Web3(new Web3.providers.HttpProvider(rpcUrl));
// 检查连接并重试
async function checkConnection(maxRetries = 3, retryDelay = 5000) {
for (let i = 0; i < maxRetries; i++) {
try {
const isListening = await web3.eth.net.isListening();
if (isListening) {
console.log('Connected to network');
return true;
}
} catch (error) {
console.error(Connection attempt ${i + 1} failed:, error.message);
}
if (i < maxRetries - 1) {
console.log(Retrying in ${retryDelay / 1000} seconds...);
await new Promise(resolve => setTimeout(resolve, retryDelay));
}
}
console.error('Unable to connect to network after', maxRetries, 'attempts');
return false;
}
// 获取网络信息
async function getNetworkInfo() {
try {
const blockNumber = await web3.eth.getBlockNumber();
const gasPrice = await web3.eth.getGasPrice();
const networkId = await web3.eth.net.getId();
const isListening = await web3.eth.net.isListening();
const peerCount = await web3.eth.net.getPeerCount();
return {
blockNumber,
gasPrice,
networkId,
isListening,
peerCount
};
} catch (error) {
console.error('获取网络信息错误:', error);
throw error;
}
}
// 获取原生代币余额
async function getNativeBalance(address) {
try {
const balanceWei = await web3.eth.getBalance(address);
const balanceEth = web3.utils.fromWei(balanceWei, 'ether');
return balanceEth;
} catch (error) {
console.error('获取原生代币余额错误:', error);
throw error;
}
}
// ERC20 合约 ABI
const erc20Abi = [
{
"constant": true,
"inputs": [{ "name": "_owner", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "balance", "type": "uint256" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [{ "name": "", "type": "uint8" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [{ "name": "", "type": "string" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [{ "name": "", "type": "string" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [{ "name": "", "type": "uint256" }],
"type": "function"
}
];
// 获取 ERC20 代币余额
async function getERC20Balance(tokenAddress, userAddress) {
try {
const tokenContract = new web3.eth.Contract(erc20Abi, tokenAddress);
const balanceWei = await tokenContract.methods.balanceOf(userAddress).call();
const decimals = await tokenContract.methods.decimals().call();
const symbol = await tokenContract.methods.symbol().call();
const balance = balanceWei / (10 ** decimals);
return { balance, symbol, decimals };
} catch (error) {
console.error('获取 ERC20 余额错误:', error);
throw error;
}
}
// ERC721 合约 ABI
const erc721Abi = [
{
"constant": true,
"inputs": [{ "name": "_owner", "type": "address" }],
"name": "balanceOf",
"outputs": [{ "name": "", "type": "uint256" }],
"type": "function"
},
{
"constant": true,
"inputs": [{ "name": "_tokenId", "type": "uint256" }],
"name": "ownerOf",
"outputs": [{ "name": "", "type": "address" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "name",
"outputs": [{ "name": "", "type": "string" }],
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [{ "name": "", "type": "string" }],
"type": "function"
}
];
// 获取 ERC721 代币余额
async function getERC721Balance(tokenAddress, userAddress) {
try {
const tokenContract = new web3.eth.Contract(erc721Abi, tokenAddress);
const balance = await tokenContract.methods.balanceOf(userAddress).call();
const name = await tokenContract.methods.name().call();
const symbol = await tokenContract.methods.symbol().call();
return { balance, name, symbol };
} catch (error) {
console.error('获取 ERC721 余额错误:', error);
throw error;
}
}
// 自动发现地址持有的 ERC20 代币
async function discoverERC20Tokens(address, maxBlocks = 50000) {
try {
console.log('正在扫描 ERC20 代币...');
// 获取当前区块高度
const currentBlock = await web3.eth.getBlockNumber();
const fromBlock = Math.max(0, currentBlock - maxBlocks);
// ERC20 Transfer 事件签名
const transferEventSignature = web3.utils.keccak256('Transfer(address,address,uint256)');
console.log(扫描区块范围: ${fromBlock} 到 ${currentBlock} (共 ${currentBlock - fromBlock} 个区块));
// 查询接收 Transfer 事件 (address 作为接收方)
const receiveLogs = await web3.eth.getPastLogs({
fromBlock: fromBlock,
toBlock: 'latest',
topics: [transferEventSignature, null, web3.utils.padLeft(address, 64)]
}).catch(error => {
console.error('查询接收事件失败:', error.message);
return [];
});
// 查询发送 Transfer 事件 (address 作为发送方)
const sendLogs = await web3.eth.getPastLogs({
fromBlock: fromBlock,
toBlock: 'latest',
topics: [transferEventSignature, web3.utils.padLeft(address, 64), null]
}).catch(error => {
console.error('查询发送事件失败:', error.message);
return [];
});
// 合并所有事件
const allLogs = [...receiveLogs, ...sendLogs];
// 提取唯一的代币合约地址
const tokenAddresses = new Set();
allLogs.forEach(log => {
if (log.address) {
tokenAddresses.add(log.address.toLowerCase());
}
});
console.log(发现 ${receiveLogs.length} 个接收事件, ${sendLogs.length} 个发送事件);
console.log(发现 ${tokenAddresses.size} 个可能的 ERC20 代币合约);
return Array.from(tokenAddresses);
} catch (error) {
console.error('扫描 ERC20 代币失败:', error.message);
return [];
}
}
// 验证是否为有效的 ERC20 代币合约
async function isValidERC20Token(tokenAddress) {
try {
const tokenContract = new web3.eth.Contract(erc20Abi, tokenAddress);
// 尝试调用 ERC20 标准方法
const [symbol, decimals] = await Promise.all([
tokenContract.methods.symbol().call().catch(() => null),
tokenContract.methods.decimals().call().catch(() => null)
]);
// 如果能够成功获取 symbol 和 decimals,则认为是有效的 ERC20 代币
return symbol !== null && decimals !== null;
} catch (error) {
return false;
}
}
// 获取代币详细信息
async function getTokenDetails(tokenAddress) {
try {
const tokenContract = new web3.eth.Contract(erc20Abi, tokenAddress);
const [name, symbol, decimals, totalSupply] = await Promise.all([
tokenContract.methods.name().call().catch(() => 'Unknown'),
tokenContract.methods.symbol().call().catch(() => 'Unknown'),
tokenContract.methods.decimals().call().catch(() => 18),
tokenContract.methods.totalSupply().call().catch(() => '0')
]);
return { name, symbol, decimals, totalSupply, address: tokenAddress };
} catch (error) {
return {
name: 'Unknown',
symbol: 'Unknown',
decimals: 18,
totalSupply: '0',
address: tokenAddress
};
}
}
// 识别地址类型
async function getAddressType(address) {
try {
// 检查是否是零地址
if (address === '0x0000000000000000000000000000000000000000') {
return { type: '零地址', description: '系统预定义的零地址,通常用于代币销毁等操作' };
}
// 检查是否是预编译合约地址(前几个地址通常是预编译合约)
const addressNum = BigInt(address);
if (addressNum >= 1n && addressNum <= 9n) {
const precompiledContracts = {
1: 'ecrecover - 椭圆曲线恢复',
2: 'sha256hash - SHA256哈希',
3: 'ripemd160hash - RIPEMD160哈希',
4: 'identity - 数据复制',
5: 'modexp - 模幂运算',
6: 'alt_bn128_add - 椭圆曲线加法',
7: 'alt_bn128_mul - 椭圆曲线乘法',
8: 'alt_bn128_pairing - 椭圆曲线配对'
};
return {
type: '预编译合约',
description: precompiledContracts[Number(addressNum)] || '未知预编译合约'
};
}
// 检查是否是合约地址(通过检查是否有代码)
const code = await web3.eth.getCode(address);
if (code && code !== '0x' && code !== '0x0') {
// 进一步检查是否是ERC20/ERC721合约
try {
const tokenContract = new web3.eth.Contract(erc20Abi, address);
const symbol = await tokenContract.methods.symbol().call().catch(() => null);
if (symbol) {
return { type: 'ERC20代币合约', description: '符合ERC20标准的代币合约' };
}
} catch (e) {
// 不是ERC20合约,继续检查ERC721
try {
const nftContract = new web3.eth.Contract(erc721Abi, address);
const symbol = await nftContract.methods.symbol().call().catch(() => null);
if (symbol) {
return { type: 'ERC721 NFT合约', description: '符合ERC721标准的NFT合约' };
}
} catch (e) {
// 不是ERC721合约
}
}
return { type: '智能合约', description: '包含代码的智能合约地址' };
}
// 默认认为是外部地址
return { type: '外部地址 (EOA)', description: '由私钥控制的外部账户地址' };
} catch (error) {
return { type: '未知类型', description: 识别失败: ${error.message} };
}
}
// 主函数
(async () => {
// 检查命令行参数
let address = process.argv[2];
// 如果没有提供命令行参数,则提示用户输入
if (!address) {
// 等待连接
const isConnected = await checkConnection();
if (!isConnected) {
process.exit(1);
}
// 获取并显示网络信息
try {
const networkInfo = await getNetworkInfo();
console.log('\n=== 网络信息 ===');
console.log(区块高度: ${networkInfo.blockNumber});
console.log(Gas 价格: ${web3.utils.fromWei(networkInfo.gasPrice, 'gwei')} Gwei);
console.log(网络 ID: ${networkInfo.networkId});
console.log(连接状态: ${networkInfo.isListening ? '已连接' : '未连接'});
console.log(节点数: ${networkInfo.peerCount});
console.log('===============\n');
} catch (error) {
console.error('获取网络信息失败:', error.message);
}
// 提示用户输入地址
address = readline.question('请输入要查询的地址: ');
}
// 等待连接(如果之前没有连接)
if (!address) {
const isConnected = await checkConnection();
if (!isConnected) {
process.exit(1);
}
}
// 验证地址格式
if (!web3.utils.isAddress(address)) {
console.error('无效的地址格式');
process.exit(1);
}
console.log(\n开始查询地址 ${address} 的链上数据...\n);
// 显示地址类型
const addressType = await getAddressType(address);
console.log(地址类型: ${addressType.type});
console.log(类型描述: ${addressType.description});
// 查询原生代币余额
try {
const nativeBalance = await getNativeBalance(address);
console.log(原生代币余额: ${nativeBalance} KAS);
} catch (error) {
console.error('查询原生代币余额失败:', error.message);
}
// 查询 ERC20 代币余额
console.log('\nERC20 代币查询:');
// 自动发现地址持有的 ERC20 代币
const discoveredTokens = await discoverERC20Tokens(address);
if (discoveredTokens.length > 0) {
console.log('正在验证和查询代币余额...');
let validTokenCount = 0;
let hasTokenBalance = false;
// 并行验证所有发现的代币
const validationPromises = discoveredTokens.map(async (tokenAddress) => {
const isValid = await isValidERC20Token(tokenAddress);
return { address: tokenAddress, isValid };
});
const validationResults = await Promise.all(validationPromises);
const validTokens = validationResults.filter(result => result.isValid).map(result => result.address);
console.log(验证通过 ${validTokens.length} 个有效的 ERC20 代币);
// 查询每个有效代币的余额
for (const tokenAddress of validTokens) {
try {
// 获取代币详细信息
const tokenDetails = await getTokenDetails(tokenAddress);
// 查询余额
const tokenInfo = await getERC20Balance(tokenAddress, address);
if (tokenInfo.balance > 0) {
console.log(\n${tokenDetails.symbol} (${tokenDetails.name}));
console.log( 合约地址: ${tokenAddress});
console.log( 余额: ${tokenInfo.balance});
console.log( 小数位数: ${tokenInfo.decimals});
console.log( 总供应量: ${web3.utils.fromWei(tokenDetails.totalSupply, 'ether')});
hasTokenBalance = true;
}
validTokenCount++;
} catch (error) {
console.error(查询代币 ${tokenAddress} 失败:, error.message);
}
}
if (!hasTokenBalance) {
console.log('未找到任何 ERC20 代币余额');
}
console.log(\n扫描完成: 发现 ${discoveredTokens.length} 个代币合约,其中 ${validTokenCount} 个为有效的 ERC20 代币);
} else {
console.log('未发现任何 ERC20 代币交易记录');
}
// 查询 ERC721 代币余额
console.log('\nERC721 代币查询:');
// 注意:您需要将下面的示例地址替换为实际的 ERC721 NFT 合约地址
const nftAddresses = [
// 示例 ERC721 NFT 地址(请替换为实际地址)
// '0x1234567890123456789012345678901234567890',
// '0x0987654321098765432109876543210987654321'
];
if (nftAddresses.length > 0) {
let hasNFTBalance = false;
for (const nftAddress of nftAddresses) {
try {
// 验证合约地址格式
if (!web3.utils.isAddress(nftAddress)) {
console.error(无效的 ERC721 合约地址: ${nftAddress});
continue;
}
const nftInfo = await getERC721Balance(nftAddress, address);
console.log(${nftInfo.name} (${nftInfo.symbol}) 余额: ${nftInfo.balance});
hasNFTBalance = true;
} catch (error) {
console.error(查询 ERC721 代币 ${nftAddress} 余额失败:, error.message);
}
}
if (!hasNFTBalance) {
console.log('未找到任何 ERC721 NFT 余额');
}
} else {
console.log('未配置 ERC721 代币地址。如果您想查询 ERC721 NFT 余额,请在代码中添加 NFT 合约地址。');
}
console.log('\n查询完成!');
})();
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
感动 | 同情 | 无聊 | 愤怒 | 搞笑 | 难过 | 高兴 | 路过 |
相关文章
-
没有相关内容