transaction-receipt (On-chain receipt translator)
name: transaction-receipt
by bevanding · published 2026-04-01
$ claw add gh:bevanding/bevanding-transaction-receipt---
name: transaction-receipt
version: 1.1.2
description: >
Human-readable on-chain transaction receipt. Resolve tx status, fees, and intent:
simple transfers, swaps/trades, token approvals, DeFi staking-style calls, and NFT
mint/transfer. Optional Tokenview API key; falls back to public read-only sources
when unset or invalid. Timeouts, rate limits, and response validation included.
author: Antalpha AI Team
requires: [curl]
metadata:
repository: https://github.com/AntalphaAI/transaction-receipt
install:
type: instruction-only
env:
- name: TOKENVIEW_API_KEY
description: Tokenview API key for comprehensive transaction data
required: false
sensitive: true
- name: TRANSACTION_RECEIPT_MAX_PER_HOUR
description: Hourly query limit (default 30)
required: false
- name: TRANSACTION_RECEIPT_RATE_FILE
description: Custom path for rate limit log file
required: false
---
# transaction-receipt (On-chain receipt translator)
Environment and configuration
| Variable | Required | Secret | If missing |
|----------|----------|--------|------------|
| `TOKENVIEW_API_KEY` | No | Yes | Do not call Tokenview; use **public Fallback** (below). Recommend users obtain a key at [tokenview.io](https://tokenview.io) for richer, more uniform payloads. |
| `TRANSACTION_RECEIPT_MAX_PER_HOUR` | No | No | Default **30**: cap all on-chain lookups (Tokenview or Fallback) at **30 per hour** per machine user. |
| `TRANSACTION_RECEIPT_RATE_FILE` | No | No | Default to `~/.openclaw/state/transaction-receipt/rate-limit.log`. Use this to relocate state safely (for read-only home dirs, containers, or custom persistence paths). |
**Dependency:** `curl` must be available. If not, explain that this skill cannot run and suggest installing `curl`. Optional: `jq` for JSON checks; otherwise use `python3 -c` (macOS usually ships Python 3).
---
API key flow (user-first, then public, then friendly failure)
1. **Prefer the user’s key:** At onboarding or before the first lookup of a session, **gently** ask whether they have configured `TOKENVIEW_API_KEY` in their environment or OpenClaw settings (do **not** ask them to paste the full key in chat).
2. **If a key is configured (non-empty):** Use Tokenview as the primary path.
3. **If no key is configured:** Use **only** the public Fallback path—this is normal, not an error.
4. **If a key is configured but invalid / expired:** After detecting auth failure, **automatically** switch to Fallback and briefly tell the user: e.g. “Your Tokenview key could not be used; results are from a public data source instead.”
5. **If both paths fail or the tx cannot be found:** Give a **short, friendly** message (network issue, wrong chain, not yet broadcast, hash typo, or rate limit). **Do not** dump raw responses.
Never echo, display, or ask the user to paste a complete API key.
---
Onboarding (first-time users)
If the user seems new, say something like:
> Welcome! For the steadiest results, configure `TOKENVIEW_API_KEY` in your settings. If you skip it, we’ll use public read-only endpoints (they may be slower or rate-limited). You can get a key at [tokenview.io](https://tokenview.io).
---
When to activate
Enable when the user uses this skill or when a message contains an extractable on-chain hash:
1. **BTC txid:** exactly **64** hex chars (`0-9`, `a-f`, `A-F`), **no** `0x` prefix.
2. **EVM tx hash:** starts with **`0x`**, total length **66**, next **64** chars are hex.
**Bounded input:** After `trim`, take the **first** token that passes validation. Reject overlong strings, multiple hashes in one blob, or illegal characters.
---
Rate limiting (P0 — before any on-chain request)
**Goal:** Avoid burning Tokenview quota or getting public nodes blocked.
1. Resolve hourly cap: `MAX="${TRANSACTION_RECEIPT_MAX_PER_HOUR:-30}"`.
2. Resolve state path in this order:
- If `TRANSACTION_RECEIPT_RATE_FILE` is set, use it directly.
- Else use `~/.openclaw/state/transaction-receipt/rate-limit.log`.
- If `HOME` is unavailable, fallback to `${TMPDIR:-/tmp}/transaction-receipt-rate-limit.log`.
3. Ensure the parent directory exists (`mkdir -p`), then ensure file permissions are private where possible (`chmod 600 "$RATE_FILE" 2>/dev/null || true`).
4. **Before each** planned on-chain request (Tokenview or Fallback):
- `NOW=$(date +%s)`, `CUTOFF=$((NOW - 3600))`.
- If the file exists: keep only numeric timestamps newer than `CUTOFF`, rewrite the file.
- Enforce a hard cap on retained rows (e.g. keep the most recent 10,000 lines) to prevent unbounded growth.
- `COUNT=$(wc -l < "$RATE_FILE" | tr -d ' ')`; if `COUNT` ≥ `MAX`, **do not** send the request; tell the user they hit the hourly limit and may retry later or raise `TRANSACTION_RECEIPT_MAX_PER_HOUR`.
- If under cap: `echo "$NOW" >> "$RATE_FILE"`, then proceed.
5. If the state file cannot be written (permission or filesystem issue), continue with an in-memory/session-only counter and clearly note that rate limiting persistence is degraded.
Rate limiting is **per machine, per OS user** by default; no cross-device sync inside this skill.
---
Actions (data routing)
Shared: curl timeouts (P0)
Every `curl` call **must** include:
`--connect-timeout 5 --max-time 30`
1. Extract hash and environment
Extract `HASH` from user input. Treat non-empty `TOKENVIEW_API_KEY` as “key configured.”
2. Source selection
3-A. Primary: Tokenview (GET)
After rate limit, run (expand `HASH` / key in the shell; **never** print full URL or key to the user):
**EVM** (`HASH` starts with `0x`):
curl -sS --connect-timeout 5 --max-time 30 \
"https://services.tokenview.io/vipapi/tx/eth/${HASH}?apikey=${TOKENVIEW_API_KEY}"**BTC** (64 hex, no `0x`):
curl -sS --connect-timeout 5 --max-time 30 \
"https://services.tokenview.io/vipapi/tx/btc/${HASH}?apikey=${TOKENVIEW_API_KEY}"Doc shorthand: `https://services.tokenview.io/vipapi/tx/eth|btc/{{hash}}?apikey={{TOKENVIEW_API_KEY}}` (still use curl timeouts).
3-B. Fallback: public read-only (no key or bad key)
Use when **no key** or **Tokenview auth failure**. Same rate limit and curl timeouts.
**EVM:** JSON-RPC POST (example mainnet: `https://ethereum.publicnode.com`; one silent retry on another public endpoint such as `https://1rpc.io/eth` is allowed—do **not** paste verbose retry logs to the user).
1. `eth_getTransactionByHash`:
curl -sS --connect-timeout 5 --max-time 30 -X POST \
-H "Content-Type: application/json" \
-d "{\"jsonrpc\":\"2.0\",\"method\":\"eth_getTransactionByHash\",\"params\":[\"${HASH}\"],\"id\":1}" \
"https://ethereum.publicnode.com"2. If `result` is not null, call `eth_getTransactionReceipt` with the same URL and `params: ["${HASH}"]` for success/failure (`status`) and **logs** (needed to classify Swap / Approve / NFT / staking).
**Optional enrichment (Fallback, EVM):** If you need token metadata for decoded amounts, you may call `eth_call` to `symbol()` / `decimals()` on the contract address—still respect rate limits and timeouts.
**BTC:** GET Blockstream:
curl -sS --connect-timeout 5 --max-time 30 \
"https://blockstream.info/api/tx/${HASH}"404 / 429: map to friendly errors; never paste huge raw JSON.
3-C. Tokenview key validity
If `TOKENVIEW_API_KEY` is set:
1. HTTP **401/403** → switch to Fallback.
2. Body indicates invalid key / forbidden / unauthorized (case-insensitive) → Fallback.
3. If Fallback also fails, one short user-facing error—no dual full payloads.
---
Scope of txid interpretation (beyond “plain transfer”)
The skill applies to **any** valid BTC or EVM tx hash. After you have validated JSON (Tokenview or RPC), **classify** the interaction and tailor the narrative:
A. Simple transfer (native or ERC-20)
B. Swap / trade (DEX aggregation, router calls, etc.)
C. Approve (ERC-20 allowance)
D. DeFi: stake / unstake / deposit / withdraw / claim (and similar)
E. NFT: mint / transfer (ERC-721 / ERC-1155)
F. Other complex contract calls
**Never invent** token amounts, counterparties, or protocol names not supported by validated data.
---
Response validation (P1)
Before writing the receipt, **validate** structure. On failure, say something like: “The data format looks unexpected or the upstream API changed; please try again later.” **Do not fabricate** balances or status.
**General:** Body must be valid JSON (`python3 -c 'import json,sys; json.load(sys.stdin)'` or `jq`).
**Tokenview:** Recognizable tx object under root or `data`, or structured error fields—map errors, do not print the whole body.
**EVM JSON-RPC:** `jsonrpc` is `"2.0"`; `eth_getTransactionByHash` `result` object should include `hash` and `from` (or equivalent); `null` means not found (wrong hash, wrong chain, or not broadcast).
**BTC Blockstream:** top-level must include `txid`.
Validation is **internal**; do not print schemas or raw bodies to the user.
---
Errors and degradation
---
Voice and output shape
**Voice:** Calm, patient **Web3 concierge**.
**Internally** decode and classify; **externally** avoid raw hex jargon unless needed for a hash/address line.
**Receipt must include:**
1. **Status:** success / failed / pending (with plain wording).
2. **Overview:** chain (BTC / EVM), **full** tx hash, time if known, block / height if known, confirmations if known.
3. **Interaction summary:** per classification above (transfer / swap paid↔received / ⚠️ approve / NFT / DeFi / generic contract).
4. **Fees:** clear units; EVM include `gasUsed` and effective gas price when available; BTC include fee rate if available.
5. **One-line takeaway:** plain-language wrap-up.
6. **Footer (required, last line only):** `Data aggregated by Antalpha AI`
Final checks before send (mandatory)
1. If the body lacks the footer, append **one** line: `Data aggregated by Antalpha AI`
2. Remove any of these if they appear in the body:
- `Sourced from public Ethereum RPC`
- `transaction-receipt v1.1.1`
3. Do **not** print version banners (e.g. `transaction-receipt v*`, bare `v1.x.x`).
4. The **last line** of the message must be **exactly** `Data aggregated by Antalpha AI` (no trailing text, blank lines, or ellipsis after it).
**Presentation:**
---
Security (production)
---
Versioning
More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...