portal-query-evm-logs

📁 subsquid-labs/agent-skills 📅 1 day ago
2
总安装量
2
周安装量
#64380
全站排名
安装命令
npx skills add https://github.com/subsquid-labs/agent-skills --skill portal-query-evm-logs

Agent 安装分布

mcpjam 2
claude-code 2
replit 2
junie 2
windsurf 2
zencoder 2

Skill 文档

When to Use This Skill

Use this skill when you need to:

  • Track ERC20 token transfers (Transfer events)
  • Monitor DeFi protocol events (Swap, Deposit, Withdraw, etc.)
  • Find events emitted by specific contracts
  • Filter events by indexed parameters (addresses, token IDs, etc.)
  • Analyze historical on-chain activity

This is the most common Portal use case – most blockchain data analysis involves event logs.


Query Structure

Portal Stream API uses POST requests with JSON payloads to /datasets/{dataset-name}/stream.

Basic EVM log query structure:

{
  "type": "evm",
  "fromBlock": 19500000,
  "toBlock": 19500100,
  "logs": [{
    "address": ["0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"],
    "topic0": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "fields": {
    "log": {
      "address": true,
      "topics": true,
      "data": true,
      "transactionHash": true
    }
  }
}

Field explanations:

  • type: "evm" – Required for EVM chains
  • fromBlock/toBlock – Block range (required)
  • logs – Array of log filter objects
  • address – Contract addresses to filter (INDEXED – fast)
  • topic0 – Event signature hash (INDEXED – fast)
  • topic1/2/3 – Indexed event parameters (INDEXED – fast)
  • fields – Which fields to include in response (optimize payload size)

Understanding Event Topics

EVM event logs use topics for indexed parameters:

event Transfer(address indexed from, address indexed to, uint256 amount);

Maps to:

  • topic0 = keccak256(“Transfer(address,address,uint256)”) = 0xddf252ad...
  • topic1 = indexed from address (padded to 32 bytes)
  • topic2 = indexed to address (padded to 32 bytes)
  • data = non-indexed parameters (amount)

Key rules:

  1. topic0 is ALWAYS the event signature hash
  2. topic1-3 are indexed parameters in declaration order
  3. Non-indexed parameters go in data field
  4. Anonymous events don’t have topic0 (rare)

Examples

Example 1: Track USDC Transfers on Base

Use case: Monitor all USDC transfer events on Base mainnet.

{
  "type": "evm",
  "fromBlock": 10000000,
  "toBlock": 10000100,
  "logs": [{
    "address": ["0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"],
    "topic0": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "fields": {
    "log": {
      "address": true,
      "topics": true,
      "data": true,
      "transactionHash": true,
      "blockNumber": true
    }
  }
}

Dataset: base-mainnet Contract: USDC on Base (0x833589fcd6edb6e08f4c7c32d4f71b54bda02913) Event: Transfer(address indexed from, address indexed to, uint256 amount)


Example 2: Find Transfers FROM Specific Address

Use case: Track all ERC20 transfers sent by a specific wallet.

{
  "type": "evm",
  "fromBlock": 19500000,
  "logs": [{
    "topic0": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],
    "topic1": ["0x000000000000000000000000d8da6bf26964af9d7eed9e03e53415d37aa96045"]
  }],
  "fields": {
    "log": {
      "address": true,
      "topics": true,
      "data": true
    }
  }
}

Notes:

  • topic1 = sender address (vitalik.eth)
  • Address is padded to 32 bytes with leading zeros
  • Omitting address filter searches ALL contracts (slower but comprehensive)

Example 3: Uniswap V3 Swap Events

Use case: Track Uniswap V3 pool swap events on Ethereum.

{
  "type": "evm",
  "fromBlock": 19500000,
  "toBlock": 19500100,
  "logs": [{
    "address": ["0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640"],
    "topic0": ["0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"]
  }],
  "fields": {
    "log": {
      "address": true,
      "topics": true,
      "data": true,
      "blockNumber": true,
      "transactionHash": true
    }
  }
}

Dataset: ethereum-mainnet Contract: USDC/WETH 0.05% pool Event: Swap(address indexed sender, address indexed recipient, int256 amount0, int256 amount1, uint160 sqrtPriceX96, uint128 liquidity, int24 tick)


Example 4: Multiple Event Types from Same Contract

Use case: Track both Deposit and Withdraw events from Aave lending pool.

{
  "type": "evm",
  "fromBlock": 19500000,
  "logs": [
    {
      "address": ["0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"],
      "topic0": ["0xde6857219544bb5b7746f48ed30be6386fefc61b2f864cacf559893bf50fd951"]
    },
    {
      "address": ["0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2"],
      "topic0": ["0x3115d1449a7b732c986cba18244e897a450f61e1bb8d589cd2e69e6c8924f9f7"]
    }
  ],
  "fields": {
    "log": {
      "address": true,
      "topics": true,
      "data": true
    }
  }
}

Notes:

  • Multiple filter objects in logs array = OR logic
  • Both Deposit and Withdraw events will be returned
  • Same contract address for both filters

Example 5: NFT Transfers to Specific Address

Use case: Track NFT transfers to a specific wallet address.

{
  "type": "evm",
  "fromBlock": 17000000,
  "toBlock": 17001000,
  "logs": [{
    "address": ["0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"],
    "topic0": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],
    "topic2": ["0x000000000000000000000000742d35cc6634c0532925a3b844bc454e4438f44e"]
  }],
  "fields": {
    "log": {
      "address": true,
      "topics": true,
      "data": true,
      "transactionHash": true,
      "blockNumber": true
    }
  }
}

Dataset: ethereum-mainnet Contract: Bored Ape Yacht Club Event: Transfer(address indexed from, address indexed to, uint256 indexed tokenId) Filter: NFTs transferred TO a specific address (topic2) Notes:

  • ERC721 Transfer events have 3 indexed parameters: from, to, tokenId
  • topic1 = from address, topic2 = to address, topic3 = token ID
  • Compare with ERC20: only 2 indexed parameters (from, to), amount is in data

Example 6: Query Multiple ERC-20 Tokens Simultaneously

Use case: Track transfers across multiple stablecoins (USDC, USDT, DAI) in one query.

{
  "type": "evm",
  "fromBlock": 18000000,
  "toBlock": 18010000,
  "logs": [{
    "address": [
      "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
      "0xdAC17F958D2ee523a2206206994597C13D831ec7",
      "0x6B175474E89094C44Da98b954EedeAC495271d0F"
    ],
    "topic0": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "fields": {
    "block": {
      "number": true,
      "timestamp": true
    },
    "log": {
      "address": true,
      "topics": true,
      "data": true,
      "transactionHash": true
    }
  }
}

Dataset: ethereum-mainnet Contracts: USDC, USDT, DAI Notes:

  • Multiple addresses in array = OR logic (matches any of the addresses)
  • Including block fields allows timestamping events
  • Efficient way to track multiple tokens without separate queries

Example 7: Monitor NFT Minting Events

Use case: Capture NFT creation events (transfers from zero address).

{
  "type": "evm",
  "fromBlock": 18000000,
  "toBlock": 18010000,
  "logs": [{
    "address": ["0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D"],
    "topic0": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"],
    "topic1": ["0x0000000000000000000000000000000000000000000000000000000000000000"]
  }],
  "fields": {
    "log": {
      "address": true,
      "topics": true,
      "transactionHash": true,
      "blockNumber": true
    }
  }
}

Dataset: ethereum-mainnet Contract: Bored Ape Yacht Club Notes:

  • Minting is represented as a transfer from the zero address
  • topic1 = zero address (0x000…000 padded to 32 bytes)
  • topic2 = recipient address (minter)
  • topic3 = token ID

Example 8: Track ERC-1155 Multi-Token Transfers

Use case: Monitor ERC-1155 TransferSingle and TransferBatch events.

{
  "type": "evm",
  "fromBlock": 18000000,
  "toBlock": 18010000,
  "logs": [{
    "address": ["0x495f947276749Ce646f68AC8c248420045cb7b5e"],
    "topic0": [
      "0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62",
      "0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb"
    ]
  }],
  "fields": {
    "log": {
      "address": true,
      "topics": true,
      "data": true
    }
  }
}

Dataset: ethereum-mainnet Contract: OpenSea Shared Storefront (ERC-1155) Event Signatures:

  • TransferSingle: 0xc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62
  • TransferBatch: 0x4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb

Notes:

  • ERC-1155 uses separate signatures for single vs batch transfers
  • Both signatures must be queried to capture complete transfer activity
  • data field contains encoded quantity information

Example 9: Monitor Multiple NFT Collections

Use case: Track transfers across popular NFT collections (BAYC, MAYC, CryptoPunks).

{
  "type": "evm",
  "fromBlock": 18000000,
  "toBlock": 18010000,
  "logs": [{
    "address": [
      "0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D",
      "0x60E4d786628Fea6478F785A6d7e704777c86a7c6",
      "0xb47e3cd837dDF8e4c57F05d70Ab865de6e193BBB"
    ],
    "topic0": ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"]
  }],
  "fields": {
    "block": {
      "number": true,
      "timestamp": true
    },
    "log": {
      "address": true,
      "topics": true,
      "transactionHash": true
    }
  }
}

Dataset: ethereum-mainnet Contracts: BAYC, MAYC, CryptoPunks Notes:

  • Multi-collection filtering with single query
  • Transfer event signature uniform across ERC-721 contracts
  • Indexed parameters contain from, to, and tokenID

Key Concepts

1. Indexed vs Non-Indexed Parameters

Indexed parameters (up to 3):

  • Stored in topic1, topic2, topic3
  • Filterable via Portal API
  • Padded to 32 bytes
  • Fast to query

Non-indexed parameters:

  • Stored in data field (ABI-encoded)
  • NOT filterable via Portal API
  • Must decode client-side
  • Smaller storage footprint

Rule: Use indexed parameters for fields you need to filter by.


2. Filter Performance Optimization

Field index status:

  • address – INDEXED (fast)
  • topic0 – INDEXED (fast)
  • topic1/2/3 – INDEXED (fast)
  • data – NOT INDEXED (can’t filter)
  • blockNumber – INDEXED (fast)
  • transactionIndex – INDEXED (fast)

Best practices:

  1. Always filter by address if you know the contract (10-100x faster)
  2. Add topic0 filter for specific events (another 10x faster)
  3. Add topic1-3 filters for further narrowing
  4. Use narrow block ranges when possible

Performance comparison:

No filters: 1M+ logs/sec → Timeout risk
address only: ~100K logs/sec → Usually safe
address + topic0: ~10K logs/sec → Fast
address + topic0 + topic1: <1K logs/sec → Very fast

3. Field Selection Strategy

Minimize payload size by requesting only needed fields:

{
  "fields": {
    "log": {
      "address": true,        // Contract address
      "topics": true,         // All topics array
      "data": true,           // Event data
      "transactionHash": true,// Tx hash
      "blockNumber": true,    // Block number
      "logIndex": true,       // Position in block
      "removed": true         // Chain reorg flag
    }
  }
}

Common minimal field sets:

  • Event tracking: address, topics, data, transactionHash
  • Volume analysis: address, topics, blockNumber
  • Full context: all fields

Note: Requesting fewer fields = smaller response = faster transfer.


4. Topic Padding Rules

Addresses in topics must be padded to 32 bytes:

Original: 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045
Padded:   0x000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045

Padding rules:

  • Addresses: left-pad with zeros (24 zeros + 20-byte address)
  • uint256: already 32 bytes (no padding needed)
  • uint8/16/32/etc: left-pad with zeros
  • bytes32: no padding needed

Tool: Use ethers.js zeroPadValue() or manually pad.


Common Mistakes

❌ Mistake 1: Filtering by Non-Indexed Parameter

{
  "logs": [{
    "address": ["0x..."],
    "topic0": ["0x..."],
    "data": ["0x1234..."]  // ❌ Can't filter by data
  }]
}

Fix: Only topic0-3 are filterable. To filter by non-indexed params, fetch all events and filter client-side.


❌ Mistake 2: Forgetting Topic Padding

{
  "topic1": ["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]  // ❌ Not padded
}

Fix: Always pad addresses to 32 bytes:

{
  "topic1": ["0x000000000000000000000000d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"]
}

❌ Mistake 3: Using Wrong Event Signature

{
  "topic0": ["0x123..."]  // ❌ Incorrect hash
}

Fix: Compute correct keccak256 hash:

  • Function: Transfer(address,address,uint256)
  • No spaces, exact types
  • Use ethers.js: ethers.id("Transfer(address,address,uint256)")

❌ Mistake 4: Too Broad Query (No Filters)

{
  "type": "evm",
  "fromBlock": 0,
  "logs": [{}]  // ❌ No filters = millions of logs
}

Fix: Always filter by at least address or topic0, and use reasonable block ranges.


❌ Mistake 5: Wrong Dataset Name

// POST /datasets/arbitrum/stream  ❌ Wrong name

Fix: Use correct Portal dataset names:

  • ethereum-mainnet (not “ethereum”)
  • arbitrum-one (not “arbitrum”)
  • base-mainnet (not “base”)

See portal-dataset-discovery skill for full mapping.


Response Format

Portal returns JSON Lines (one JSON object per line):

{"header":{"blockNumber":19500000,"hash":"0x...","parentHash":"0x...","timestamp":1234567890}}
{"logs":[{"address":"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913","topics":["0xddf252ad...","0x000...123","0x000...456"],"data":"0x000...789","transactionHash":"0xabc...","logIndex":42}]}
{"logs":[{"address":"0x833589fcd6edb6e08f4c7c32d4f71b54bda02913","topics":["0xddf252ad...","0x000...111","0x000...222"],"data":"0x000...333","transactionHash":"0xdef...","logIndex":18}]}

Parsing:

  1. Split response by newlines
  2. Parse each line as JSON
  3. First line is block header
  4. Subsequent lines contain logs array

Related Skills

  • portal-query-evm-transactions – Query transactions that emitted these logs
  • portal-query-evm-traces – Track internal calls related to events
  • portal-dataset-discovery – Find correct dataset name for your chain
  • pipes-abi – Get ABI and event signatures for contracts

Additional Resources

Official Subsquid Documentation

Core Documentation

  • llms.txt – Quick reference for Portal API logs querying
  • llms-full.txt – Complete Portal documentation
  • skill.md – Comprehensive Portal API guide

API Resources