您现在的位置:kastop>> Kas信息 Web3信息>>正文内容

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查询完成!');

})();



感动 同情 无聊 愤怒 搞笑 难过 高兴 路过
【字体: 】【收藏】【打印文章】 【 打赏 】 【查看评论

相关文章

    没有相关内容