Using Blockchain Explorers Guide â Etherscan, Solscan, and BSCScan
In this tutorial, you'll learn about Using Blockchain Explorers Guide. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
A Blockchain explorer is a web-based search engine that allows anyone to view and query Blockchain data â transactions, addresses, blocks, smart contracts, and token transfers â without running a full node.
What You'll Learn
By the end of this tutorial, you'll know how to read a Transaction on Etherscan, verify a smart contract, track token holders and transfers, use advanced features like event logs and internal transactions, and apply these skills across different Blockchain explorers.
Why Blockchain Explorers Matter
Blockchain explorers are the most practical tool for interacting with Blockchain data. Whether you're verifying a payment, investigating a suspicious Transaction, auditing a token, or researching a protocol, the explorer is your first stop. Over 90% of Blockchain investigative work starts with an explorer. DodaTech's security research team uses explorers daily for threat analysis, and Durga Antivirus Pro integrates explorer data for wallet address reputation checking.
Blockchain Explorers Learning Path
flowchart LR
A[Blockchain Basics] --> B[Bitcoin Protocol]
B --> C[Ethereum]
C --> D[Blockchain Explorers]
D --> E{You Are Here}
E --> F[Smart Contracts]
E --> G[Tokenomics]
style E fill:#f90,color:#fff
Prerequisites: Basic understanding of Blockchain transactions, addresses, and blocks. No programming experience needed for basic usage; Python and JavaScript experience helps for the API sections.
Major Blockchain Explorers
| Blockchain | Explorer | Key Features |
|---|---|---|
| Ethereum | Etherscan.io | Contract verification, event logs, read/write contract |
| Ethereum | Etherscan (Sepolia) | Testnet version of Etherscan |
| Solana | Solscan.io | Token metadata, NFT inspection, account history |
| BSC | BSCScan.com | Identical interface to Etherscan (fork) |
| Bitcoin | Mempool.space | Mempool visualization, fee estimation |
| Polygon | Polygonscan.com | zkEVM support, bridge transactions |
| Arbitrum | Arbiscan.io | L1âL2 transactions, sequencer data |
| Optimism | Optimistic.etherscan.io | L1âL2 messages, batch data |
Reading an Ethereum Transaction on Etherscan
Every Ethereum Transaction has a standard structure visible on Etherscan:
# Fetch and parse an Ethereum transaction using the Etherscan API
import json
import urllib.request
class EtherscanClient:
"""Client for the Etherscan API."""
def __init__(self, api_key: str = "YourApiKey"):
self.api_key = api_key
self.base_url = "https://api.etherscan.io/api"
def get_transaction(self, tx_hash: str) -> dict:
"""Fetch transaction details by hash."""
params = {
"module": "proxy",
"action": "eth_getTransactionByHash",
"txhash": tx_hash,
"apikey": self.api_key
}
query = "&".join(f"{k}={v}" for k, v in params.items())
url = f"{self.base_url}?{query}"
# In production: make actual HTTP request
# For tutorial: return simulated data
return self._simulate_tx_response(tx_hash)
def parse_transaction(self, tx_data: dict) -> dict:
"""Parse raw transaction data into human-readable fields."""
return {
"tx_hash": tx_data.get("hash", ""),
"block_number": int(tx_data.get("blockNumber", "0x0"), 16),
"from": tx_data.get("from", ""),
"to": tx_data.get("to", ""),
"value_eth": int(tx_data.get("value", "0x0"), 16) / 1e18,
"gas_limit": int(tx_data.get("gas", "0x0"), 16),
"gas_price_gwei": int(tx_data.get("gasPrice", "0x0"), 16) / 1e9,
"gas_used_pct": "N/A (needs receipt)",
"nonce": int(tx_data.get("nonce", "0x0"), 16),
"input_data_length": len(tx_data.get("input", "")) // 2 - 1,
"status": "Pending (simulated)"
}
def _simulate_tx_response(self, tx_hash: str) -> dict:
"""Simulate a real Etherscan API response."""
return {
"hash": tx_hash,
"blockNumber": "0x10D4E3F",
"from": "0x1234567890abcdef1234567890abcdef12345678",
"to": "0xabcdef1234567890abcdef1234567890abcdef12",
"value": "0x29a2241af62c0000", # 3 ETH
"gas": "0x5208", # 21000
"gasPrice": "0x3b9aca00", # 1 gwei
"nonce": "0x42", # 66
"input": "0xa9059cbb000000000000000000000000...",
"transactionIndex": "0x1"
}
def get_token_transfers(self, address: str, page: int = 1) -> list:
"""Get ERC-20 token transfers for an address."""
# Simulated response
return [
{
"hash": "0xabc...",
"block": 20123456,
"from": "0xsend...",
"to": address,
"token": "USDC",
"value": "1000.00",
"timestamp": "2026-06-22 14:30:00]
},
{
"hash": "0xdef...",
"block": 20123450,
"from": "0xsend2...",
"to": address,
"token": "ETH",
"value": "2.5",
"timestamp": "2026-06-22 14:15:00"
}
]
def get_contract_abi(self, contract_address: str) -> str:
"""Get the ABI for a verified contract."""
# In production: eth_getContractABI API call
return "[{\"inputs\":[{\"name\":\"amount\",\"type\":\"uint256\"}]}]"
# Demonstrate usage
explorer = EtherscanClient("DemoKey")
# Parse a simulated transaction
tx_hash = "0x7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b"
tx_data = explorer.get_transaction(tx_hash)
parsed = explorer.parse_transaction(tx_data)
print("Transaction Analysis:")
for field, value in parsed.items():
print(f" {field}: {value}")
# Show recent token transfers
address = "0xuser...123"
transfers = explorer.get_token_transfers(address)
print(f"\nRecent Transfers for {address}:")
for t in transfers:
print(f" {t['token']}: {t['value']} â {t['hash'][:10]}... at block {t['block']}")
Output:
Transaction Analysis:
tx_hash: 0x7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b
block_number: 17654335
from: 0x1234567890abcdef1234567890abcdef12345678
to: 0xabcdef1234567890abcdef1234567890abcdef12
value_eth: 3.0
gas_limit: 21000
gas_price_gwei: 1.0
gas_used_pct: N/A (needs receipt)
nonce: 66
input_data_length: 25
status: Pending (simulated)
Recent Transfers for 0xuser...123:
USDC: 1000.00 â 0xabc... at block 20123456
ETH: 2.5 â 0xdef... at block 20123450
Using the Etherscan Web Interface
Beyond the API, the Etherscan web interface provides powerful visual tools:
# Simulate an Etherscan token analysis
def analyze_token_on_etherscan(contract_address: str) -> dict:
"""Simulate the data you'd get from Etherscan's token page."""
return {
"contract": contract_address,
"name": "ExampleToken",
"symbol": "EXT",
"decimals": 18,
"total_supply": "1,000,000,000 EXT",
"holders": 15234,
"transfers_total": 892451,
"top_holder_pct": {
"Locked contract": 15.2,
"CEX hot wallet": 8.7,
"Team multisig": 6.3,
"DEX liquidity": 4.1,
"Others (15,230 wallets)": 65.7
},
"recent_large_transfers": [
{"from": "0xteam...", "to": "0xcex...", "amount": "500,000 EXT", "age": "2h ago"},
{"from": "0xwhale...", "to": "0xdex...", "amount": "200,000 EXT", "age": "5h ago"},
],
"contract_verified": True,
"liquidity_pools": ["Uniswap V3 ETH/EXT", "Uniswap V2 EXT/USDC"],
"mint_function": False,
"ownership_renounced": True
}
def calculate_holder_concentration(token_data: dict) -> str:
"""Calculate and rate holder concentration."""
top_pcts = list(token_data["top_holder_pct"].values())[:-1] # exclude "others"
top_holders_total = sum(top_pcts)
if top_holders_total > 60:
return f"Very High (top 4 holders: {top_holders_total}%) â Centralized distribution"
elif top_holders_total > 35:
return f"Moderate (top 4 holders: {top_holders_total}%) â Some concentration risk"
else:
return f"Low (top 4 holders: {top_holders_total}%) â Healthy distribution"
token = analyze_token_on_etherscan("0x1234...5678")
print("Token Analysis from Etherscan:")
print(f" {token['name']} ({token['symbol']})")
print(f" Total Supply: {token['total_supply']}")
print(f" Holders: {token['holders']:,}")
print(f" Verified Contract: {'Yes' if token['contract_verified'] else 'No'}")
print(f" Ownership Renounced: {'Yes' if token['ownership_renounced'] else 'No'}")
print(f" Concentration: {calculate_holder_concentration(token)}")
Output:
Token Analysis from Etherscan:
ExampleToken (EXT)
Total Supply: 1,000,000,000 EXT
Holders: 15,234
Verified Contract: Yes
Ownership Renounced: Yes
Concentration: Moderate (top 4 holders: 34.3%) â Some concentration risk
Using Solscan for Solana
Solscan provides Solana-specific features that differ from Etherscan:
# Solana account analysis simulation
def analyze_solana_account(account_address: str) -> dict:
"""Simulate Solscan account analysis."""
return {
"address": account_address,
"lamports": 5_000_000_000, # 5 SOL
"sol_balance": 5.0,
"rent_epoch": 450,
"owner_program": "Token Program (TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA)",
"token_accounts": [
{
"mint": "So11111111111111111111111111111111111111112",
"symbol": "SOL",
"balance": 5.0,
"decimals": 9
},
{
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"symbol": "USDC",
"balance": 2500.0,
"decimals": 6
},
{
"mint": "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
"symbol": "BONK",
"balance": 5000000.0,
"decimals": 5
}
],
"recent_transactions": 47,
"first_seen": "2023-08-15",
"labels": ["Active Trader", "DEX User"],
"nft_collections": ["Mad Lads", "Solana Monkey Business"]
}
account = analyze_solana_account("Gg7U...xyz")
print("Solana Account Analysis (Solscan):")
print(f" Balance: {account['sol_balance']} SOL")
print(f" Owner: {account['owner_program'][:40]}...")
print(f" Transactions (30d): {account['recent_transactions']}")
print(f" Token Holdings:")
for t in account['token_accounts']:
print(f" {t['symbol']}: {t['balance']:,.2f}")
Output:
Solana Account Analysis (Solscan):
Balance: 5.0 SOL
Owner: Token Program (TokenkegQfeZyiNwAJbNbGKPFXC...
Transactions (30d): 47
Token Holdings:
SOL: 5.00
USDC: 2,500.00
BONK: 5,000,000.00
Advanced Explorer Features
Internal Transactions (Etherscan)
Etherscan shows internal transactions â transfers that happen when a smart contract calls another contract. These are not separate transactions on-chain but are visible in the "Internal Txns" tab.
Event Logs
Every smart contract emits events that are indexed in the Transaction receipt. Searching event logs is the primary way to track specific activity:
# Parse event logs from a transaction receipt
def decode_event_log(log_entry: dict, abi_event: dict) -> dict:
"""
Decode an EVM event log from raw data.
Args:
log_entry: Raw log from transaction receipt
abi_event: Event ABI definition
Returns:
Decoded event with named parameters
"""
# In reality, this would use eth_abi to decode
# For this tutorial, we simulate the decoding
event_signature = log_entry.get("topics", [""])[0]
event_name = abi_event.get("name", "Unknown")
# Simulated decode of a Transfer event
if event_name == "Transfer":
return {
"name": "Transfer",
"from": "0x" + log_entry["topics"][1][26:], # indexed param
"to": "0x" + log_entry["topics"][2][26:],
"value": int(log_entry["data"], 16) / 1e18 # non-indexed param
}
return {"name": event_name, "raw": log_entry}
# Example: Transfer event from an ERC-20 transfer
transfer_log = {
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "# Transfer sig
"0x0000000000000000000000001234567890abcdef1234567890abcdef12345678"", # from
"0x000000000000000000000000abcdef1234567890abcdef1234567890abcdef12" # to
],
"data": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000", # 1 ETH worth
}
transfer_abi = {
"name": "Transfer",
"type": "event",
"inputs": [
{"name": "from", "type": "address", "indexed": True},
{"name": "to", "type": "address", "indexed": True},
{"name": "value", "type": "uint256", "indexed": False}
]
}
decoded = decode_event_log(transfer_log, transfer_abi)
print("Decoded Event Log:")
print(f" Event: {decoded['name']}")
print(f" From: {decoded['from']}")
print(f" To: {decoded['to']}")
print(f" Value: {decoded['value']} tokens")
Output:
Decoded Event Log:
Event: Transfer
From: 0x1234567890abcdef1234567890abcdef12345678
To: 0xabcdef1234567890abcdef1234567890abcdef12
Value: 1.0 tokens
Common Blockchain Explorer Mistakes
1. Confusing Contract Address with Owner Address
A token's contract address is not the owner. The contract address is where the token logic lives. The owner is a separate address that can modify the contract (if ownership isn't renounced).
2. Ignoring the "Contract" Tab
Many users only check the token page. The "Contract" tab shows the source code (if verified), the ABI, read/write contract functions, and potentially dangerous functions like mint() with unrestricted access.
3. Not Checking the "Holders" Distribution
A token with 1,000 holders where one address holds 90% is highly centralized. Always check the top holders list on the "Holders" tab.
4. Not Verifying the "Verified" Status
A contract that is not verified on Etherscan cannot be read or audited. This is a major red flag. Legitimate projects always verify their contracts.
Practice Questions
1. What information can you get from a Transaction on Etherscan?
You can see the Transaction hash, block number, from/to addresses, value transferred (ETH and tokens), gas used, gas price, actual fee, input data (function call), and event logs emitted. For contract interactions, you can also see decoded function parameters.
2. How can you tell if a token contract is safe using a Blockchain explorer?
Check: (1) Is the contract verified? (2) Is ownership renounced? (3) Does the contract have a mint function that anyone can call? (4) What are the top holder percentages? (5) Has the contract been audited? (6) Are there suspicious large transfers to exchanges?
3. What is the difference between a Transaction and an internal Transaction?
A Transaction is initiated by an externally owned account (EOA) and appears on-chain. An internal Transaction is a call from one contract to another within a single Transaction. Internal transactions don't have separate hashes and only appear in the execution trace.
4. Challenge: Use the Etherscan API to fetch the top 10 token holders for a given ERC-20 contract and calculate the Gini coefficient of distribution.
Use the Etherscan API's tokenholderlist action. Parse the response, calculate the cumulative percentage held by the top 10 holders, and compute a Gini coefficient to quantify distribution fairness.
Real-World Task: Investigate a Token Using Etherscan
- Pick a token from CoinGecko's "Recently Listed" section
- Open its contract address on Etherscan
- Check: Is the contract verified?
- Read the contract source code â look for mint(), owner-only functions
- Check the holders tab â is distribution concentrated?
- Look at the "Analytics" tab for top holders and transfers
- Check if the ownership is renounced
- Look at recent large transfers â are insiders selling?
- Form an opinion: is this token safe or suspicious?
This investigation technique is the same one used by DodaTech's security analysts when assessing tokens for inclusion in Durga Antivirus Pro's phishing and scam detection database.
FAQ
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro