You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从指定以太坊钱包地址获取ERC20、ERC721、ERC827代币列表及详情

Hey there! If you're looking to pull a list of ERC20, ERC721, and ERC827 tokens held by a specific Ethereum wallet—along with their names, symbols, logos, and balances—you’ve got two solid paths to choose from: using third-party data APIs (the quick, low-effort route) or querying an Ethereum node directly (great for custom workflows). Let’s break down both options with practical details:

一、借助第三方数据 APIs (推荐 for rapid development)

Third-party services handle the heavy lifting of indexing blockchain data, so you can focus on integrating the results. Here are the most reliable ones:

  • Etherscan API
    It has dedicated endpoints for token balances and metadata:

    • For ERC20 tokens: Use the tokentx endpoint to fetch all token transfers involving the target address, then deduplicate contract addresses. You can then call the tokeninfo endpoint for each contract to get its name, symbol, and other details.
    • For ERC721 tokens: Use the tokennfttx endpoint to retrieve NFT transfers, then fetch individual NFT metadata via contract-specific calls.
    • Logos: Etherscan hosts token logos on its CDN (format: https://etherscan.io/token/images/[contract-address-prefix]_32.png), but this only works for tokens the platform has indexed.

    Example pseudocode snippet:

    // Fetch ERC20 transfer history to get contract addresses
    const erc20TxResponse = await fetch(`https://api.etherscan.io/api?module=account&action=tokentx&address=YOUR_WALLET_ADDRESS&startblock=0&endblock=99999999&sort=asc&apikey=YOUR_API_KEY`);
    // Deduplicate contract addresses
    const uniqueContracts = [...new Set(erc20TxResponse.result.map(tx => tx.contractAddress))];
    // Fetch metadata for each contract
    const tokenMetadata = await Promise.all(uniqueContracts.map(addr => 
      fetch(`https://api.etherscan.io/api?module=token&action=tokeninfo&contractaddress=${addr}&apikey=YOUR_API_KEY`)
    ));
    
  • Alchemy NFT API
    If your focus is on ERC721 tokens, Alchemy’s NFT API lets you directly fetch all NFTs held by an address, including full metadata (images, descriptions) and balances. It also supports ERC20 token balance queries for a unified workflow.

二、自行查询 Ethereum 节点 (for custom, control-heavy workflows)

If you need full control over data processing, you can use a Web3 library (like ethers.js or web3.js) to connect to an Ethereum mainnet node (via Infura, Alchemy, or your own self-hosted node).

Core Logic Breakdown:

  1. ERC20 Tokens

    • Ethereum doesn’t have a global token registry, so you’ll need to filter Transfer events where the target wallet is the recipient. Deduplicate contract addresses from these events.
    • For each contract, call standard ERC20 methods: name(), symbol(), balanceOf(YOUR_WALLET_ADDRESS), and decimals() (to format balance correctly).
    • Logos: Parse the token’s metadata via tokenURI() (if implemented) or rely on third-party indexed data.
  2. ERC721 Tokens

    • Filter Transfer events (ERC721 uses a different signature that includes a tokenId). Deduplicate contract addresses.
    • For each contract, call name(), symbol(), and balanceOf(YOUR_WALLET_ADDRESS) to get the number of NFTs held.
    • Use tokenOfOwnerByIndex() to iterate through each held tokenId, then call tokenURI(tokenId) to fetch metadata (including images/logos).
  3. ERC827 Tokens
    ERC827 is an extension of ERC20, so you can use the same methods as ERC20 to fetch balances and metadata. Its additional functionality (executing calls with transfers) isn’t needed for basic token listing.

Example Code with ethers.js:

const { ethers } = require("ethers");

// Connect to Ethereum mainnet node
const provider = new ethers.providers.JsonRpcProvider("YOUR_NODE_URL");
const targetWallet = "0xYOUR_WALLET_ADDRESS";

// Minimal ABIs for ERC20 and ERC721
const erc20Abi = [
  "function name() view returns (string)",
  "function symbol() view returns (string)",
  "function balanceOf(address) view returns (uint256)",
  "function decimals() view returns (uint8)",
  "event Transfer(address indexed from, address indexed to, uint256 value)"
];

const erc721Abi = [
  "function name() view returns (string)",
  "function symbol() view returns (string)",
  "function balanceOf(address) view returns (uint256)",
  "function tokenOfOwnerByIndex(address, uint256) view returns (uint256)",
  "function tokenURI(uint256) view returns (string)",
  "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
];

// Fetch ERC20 tokens
async function fetchERC20Tokens() {
  const transferFilter = {
    topics: [ethers.utils.id("Transfer(address,address,uint256)")],
    to: targetWallet
  };
  const events = await provider.getLogs(transferFilter);
  const uniqueContracts = [...new Set(events.map(e => e.address))];

  const tokens = [];
  for (const addr of uniqueContracts) {
    const contract = new ethers.Contract(addr, erc20Abi, provider);
    try {
      const [name, symbol, balance, decimals] = await Promise.all([
        contract.name(),
        contract.symbol(),
        contract.balanceOf(targetWallet),
        contract.decimals()
      ]);
      tokens.push({
        contractAddress: addr,
        name,
        symbol,
        balance: ethers.utils.formatUnits(balance, decimals),
        logo: `https://etherscan.io/token/images/${addr.slice(2,6)}_32.png` // Etherscan CDN example
      });
    } catch (err) {
      // Skip non-compliant contracts
      continue;
    }
  }
  return tokens;
}

// Fetch ERC721 tokens
async function fetchERC721Tokens() {
  const transferFilter = {
    topics: [ethers.utils.id("Transfer(address,address,uint256)")],
    to: targetWallet
  };
  const events = await provider.getLogs(transferFilter);
  const uniqueContracts = [...new Set(events.map(e => e.address))];

  const nfts = [];
  for (const addr of uniqueContracts) {
    const contract = new ethers.Contract(addr, erc721Abi, provider);
    try {
      const [name, symbol, balance] = await Promise.all([
        contract.name(),
        contract.symbol(),
        contract.balanceOf(targetWallet)
      ]);
      
      const ownedNFTs = [];
      for (let i = 0; i < balance.toNumber(); i++) {
        const tokenId = await contract.tokenOfOwnerByIndex(targetWallet, i);
        const tokenURI = await contract.tokenURI(tokenId);
        const metadata = await fetch(tokenURI).then(res => res.json());
        ownedNFTs.push({ tokenId: tokenId.toString(), image: metadata.image });
      }

      nfts.push({
        contractAddress: addr,
        name,
        symbol,
        balance: balance.toString(),
        logo: ownedNFTs[0]?.image || null,
        ownedNFTs
      });
    } catch (err) {
      continue;
    }
  }
  return nfts;
}

// Execute queries
(async () => {
  const erc20s = await fetchERC20Tokens();
  const erc721s = await fetchERC721Tokens();
  console.log("ERC20 Tokens:", erc20s);
  console.log("ERC721 Tokens:", erc721s);
})();
三、Key Considerations
  • Non-compliant Contracts: Some tokens might not follow ERC standards (e.g., missing name() or symbol() methods). Add error handling to skip these.
  • Logo Reliability: There’s no universal way to fetch logos—rely on third-party indexes or token metadata URIs.
  • Performance: Direct node queries can be slow for wallets with long transaction histories. Limit your query to recent blocks or use pagination.
  • API Rate Limits: Third-party APIs have request limits—use an API key and implement rate limiting in your code.

内容的提问来源于stack exchange,提问作者Oyewole A. Samuel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:44:40