Install
openclaw skills install @lkkchen/fetch-evm-logsScaffold and fetch event logs from any EVM smart contract via RPC (eth_getLogs + ABI parse). Works on any EVM-compatible chain/contract (Ethereum, L2s, custom chains) given chainId + address + RPC. Trigger when the user asks to get, pull, fetch, sync, or download contract event logs / 合约日志 / 事件日志 / eth_getLogs — e.g.「帮我获取某个 EVM 合约的日志」 「帮我拉取智能合约的日志」「fetch logs for this contract」「get Transfer events from 0x…」. Also when they give chainId + contractAddress and want on-chain events. Discovers ABI from public sources or accepts user-provided ABI, lists events, asks which to fetch, then runs s1/s2. Pull + parse only — not for stats/analytics (use evm-log-stats).
openclaw skills install @lkkchen/fetch-evm-logsPull event logs from any EVM contract on any EVM-compatible chain (Ethereum mainnet/testnets, L2s, sidechains, custom chains) — not limited to a specific protocol or event type. You only need chainId, contractAddress, an RPC, and an ABI (auto-fetched or user-provided).
Self-contained skill: scaffold → chainId + address → get ABI → pick events → pull + parse.
init-project.sh
→ ask chainId + contractAddress (+ rpc)
→ ABI: public fetch OR user-provided
→ list events → user picks → contract.ts → pnpm s1 → pnpm s2
Templates: this skill's templates/ (no external repo).
Scope: any EVM contract / any chain that speaks JSON-RPC eth_getLogs — ERC-20, NFT, distributor, DEX, custom contracts, etc.
Use this skill when the user wants raw/on-chain event logs from an EVM smart contract. Typical asks:
| User says (examples) | Action |
|---|---|
| 「帮我获取某个 EVM 合约的日志」 | Start this skill |
| 「帮我获取 / 拉取智能合约的日志」 | Start this skill |
| 「帮我拉一下这个合约的 event / Transfer / Claim 日志」 | Start this skill |
「fetch / pull / sync logs for contract 0x…」 | Start this skill |
| 「用 eth_getLogs 拉这个地址的事件」 | Start this skill |
Gives chainId + contractAddress and wants events | Start this skill |
If they only have a vague ask (「帮我获取智能合约的日志」) without address/chainId, still start this skill, then ask for chainId + contractAddress in Step 1.
Do not use for:
If no project yet:
bash ~/.cursor/skills/fetch-evm-logs/scripts/init-project.sh [target_dir]
Default: ./fetch_evm_logs. Then continue below.
Required from user:
| Item | Required | Example |
|---|---|---|
chainId | yes | 1, 41443 |
contractAddress | yes | 0x4CcDb... |
| RPC URL | optional | public RPC for that chain if user has none |
startBlock / endBlock | optional | default 0 / 'latest' |
tokenDecimals | optional | 18 for amount fields |
Ask clearly, e.g.:
请提供
chainId和合约地址contractAddress。如有专用 RPC 也可一并提供。
ABI cannot be read from JSON-RPC bytecode alone. Two valid ways to obtain it:
node ~/.cursor/skills/fetch-evm-logs/scripts/fetch-abi.mjs \
--chainId <id> --address <0x...> --out <project>/src/abi
ETHERSCAN_API_KEY is set (or user provides a key)If public fetch fails, the contract is unverified, or the user already has the ABI — ask the user to provide it:
公开源未能找到该合约 ABI。请粘贴完整合约 ABI JSON(或至少包含目标 event 的 fragment),也可提供本地 ABI 文件路径。
Accept:
Then write it to:
src/abi/abi_{address}_{chainId}.json
(address lowercase). Do not invent or guess ABI.
node ~/.cursor/skills/fetch-evm-logs/scripts/list-events.mjs \
--abi <project>/src/abi/abi_{address}_{chainId}.json
Show the event list to the user and ask which to fetch:
该合约 ABI 中有以下 event:…
需要拉取哪些?可选:全部 / 指定若干个 event 名称。
Do not skip this confirmation when multiple events exist (unless they already said “全部”).
src/abi/abi_{address}_{chainId}.json
(address lowercase)
src/contract.tsexport const Contracts = {
contracts: {
MyContract: {
address: '0x...',
chainId: 41443,
// string OK; array = ordered failover on RPC errors
rpc: ['https://primary-rpc.example', 'https://backup-rpc.example'],
startBlock: 0,
endBlock: 'latest',
// '*' = all ABI events; or string[] of event names
eventNames: ['Transfer', 'Approval'],
tokenDecimals: 18,
},
},
};
rpc: string | string[] — on failure, retries then rotates to the next URLeventNames: '*' → pull all logs from the contract (no topic filter)eventNames: ['Foo', 'Bar'] → topic0 OR filter for those eventsaddress + chainIdcd <target_dir>
pnpm s1 # → output/{address}_{chainId}/logs.txt
pnpm s2 # → output/{address}_{chainId}/logs.json
Stop after s2.
output/{address}_{chainId}/
├── logs.txt
└── logs.json
Parsed log:
{
txHash: string;
logIndex: number;
blockNumber: number;
eventName: string;
data: Record<string, string | boolean>;
}
- [ ] Project scaffolded (if needed)
- [ ] User gave chainId + contractAddress
- [ ] ABI obtained (public fetch **or** user-provided) → abi_{address}_{chainId}.json
- [ ] Events listed; user chose which to fetch
- [ ] contract.ts configured
- [ ] pnpm s1 && pnpm s2
rpc: [...] so failover can recover from rate limits / outagespageSize in s1 (default 1000)abi_{address}_{chainId}.json (lowercase address)