Skills transaction-receipt
git clone https://github.com/openclaw/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/bevanding/transaction-receipt" ~/.claude/skills/openclaw-skills-transaction-receipt && rm -rf "$T"
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.openclaw/skills && cp -r "$T/skills/bevanding/transaction-receipt" ~/.openclaw/skills/openclaw-skills-transaction-receipt && rm -rf "$T"
skills/bevanding/transaction-receipt/SKILL.mdtransaction-receipt (On-chain receipt translator)
Environment and configuration
| Variable | Required | Secret | If missing |
|---|---|---|---|
| No | Yes | Do not call Tokenview; use public Fallback (below). Recommend users obtain a key at tokenview.io for richer, more uniform payloads. |
| No | No | Default 30: cap all on-chain lookups (Tokenview or Fallback) at 30 per hour per machine user. |
| No | No | Default to . 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)
- Prefer the user’s key: At onboarding or before the first lookup of a session, gently ask whether they have configured
in their environment or OpenClaw settings (do not ask them to paste the full key in chat).TOKENVIEW_API_KEY - If a key is configured (non-empty): Use Tokenview as the primary path.
- If no key is configured: Use only the public Fallback path—this is normal, not an error.
- 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.”
- 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
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.TOKENVIEW_API_KEY
When to activate
Enable when the user uses this skill or when a message contains an extractable on-chain hash:
- BTC txid: exactly 64 hex chars (
,0-9
,a-f
), noA-F
prefix.0x - EVM tx hash: starts with
, total length 66, next 64 chars are hex.0x
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.
- Resolve hourly cap:
.MAX="${TRANSACTION_RECEIPT_MAX_PER_HOUR:-30}" - Resolve state path in this order:
- If
is set, use it directly.TRANSACTION_RECEIPT_RATE_FILE - Else use
.~/.openclaw/state/transaction-receipt/rate-limit.log - If
is unavailable, fallback toHOME
.${TMPDIR:-/tmp}/transaction-receipt-rate-limit.log
- If
- Ensure the parent directory exists (
), then ensure file permissions are private where possible (mkdir -p
).chmod 600 "$RATE_FILE" 2>/dev/null || true - 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
, rewrite the file.CUTOFF - Enforce a hard cap on retained rows (e.g. keep the most recent 10,000 lines) to prevent unbounded growth.
; ifCOUNT=$(wc -l < "$RATE_FILE" | tr -d ' ')
≥COUNT
, do not send the request; tell the user they hit the hourly limit and may retry later or raiseMAX
.TRANSACTION_RECEIPT_MAX_PER_HOUR- If under cap:
, then proceed.echo "$NOW" >> "$RATE_FILE"
- 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
- Key configured: Tokenview first.
- Key not configured: Fallback only.
- Key configured but invalid: after auth failure, Fallback (do not stop the flow).
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).
: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"
- If
is not null, callresult
with the same URL andeth_getTransactionReceipt
for success/failure (params: ["${HASH}"]
) and logs (needed to classify Swap / Approve / NFT / staking).status
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:
- HTTP 401/403 → switch to Fallback.
- Body indicates invalid key / forbidden / unauthorized (case-insensitive) → Fallback.
- 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)
- Goal: State clearly who sent what to whom (from → to, asset, human-readable amount).
- Use
/from
/to
for native transfers; for ERC-20, infer from Transfer logs (value
typicallytopics[0]
) and decode sender, recipient, and amount (respect token decimals when known).0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef
B. Swap / trade (DEX aggregation, router calls, etc.)
- Goal: Summarize what the user paid and what they received (assets + approximate amounts).
- Use decoded logs (e.g. Swap/Sync/Mint/Burn style events), Tokenview’s decoded fields if present, or internal transfers—best effort. If legs are ambiguous, say what is certain and mark the rest as “not fully decoded.”
C. Approve (ERC-20 allowance)
- Goal: Use a warning tone.
- Clearly state: the user authorized a spender (typically
in the Approval log) to move up to X of token Y on their behalf. Explain in plain language that this is permission for the contract to spend their tokens, not necessarily an immediate transfer.spender - Do not panic-monger; be factual and prominent (e.g. “⚠️ Approval: you granted spending rights…”).
D. DeFi: stake / unstake / deposit / withdraw / claim (and similar)
- Describe the observable asset movements and the contract the user called.
- If decoding is incomplete: fallback to: “You interacted with a smart contract at
(short + full address). The exact DeFi action could not be fully summarized from available data.”0x…
E. NFT: mint / transfer (ERC-721 / ERC-1155)
- Mint: e.g. “You minted” or “NFT(s) were minted to your address,” with collection/name if available from logs or metadata hints.
- Transfer: who sent which NFT id (and quantity for 1155) to whom.
- If only
with unknown collection, still report addresses and token id.Transfer
F. Other complex contract calls
- If the tx is not clearly A–E above: use the plain-language fallback: “You performed an on-chain interaction with smart contract
.” Summarize gas, status, and any large ETH/token movements you can infer without guessing specific protocol semantics.0x…
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
- Non-2xx HTTP, timeouts, curl errors: short human explanation; no full upstream body.
- No key: Fallback only—normal path.
- Bad key: Fallback after detection; brief notice.
- Nothing found after both paths: friendly message (check network, chain, spelling, pending tx).
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:
- Status: success / failed / pending (with plain wording).
- Overview: chain (BTC / EVM), full tx hash, time if known, block / height if known, confirmations if known.
- Interaction summary: per classification above (transfer / swap paid↔received / ⚠️ approve / NFT / DeFi / generic contract).
- Fees: clear units; EVM include
and effective gas price when available; BTC include fee rate if available.gasUsed - One-line takeaway: plain-language wrap-up.
- Footer (required, last line only):
Data aggregated by Antalpha AI
Final checks before send (mandatory)
- If the body lacks the footer, append one line:
Data aggregated by Antalpha AI - Remove any of these if they appear in the body:
Sourced from public Ethereum RPCtransaction-receipt v1.1.1
- Do not print version banners (e.g.
, baretransaction-receipt v*
).v1.x.x - The last line of the message must be exactly
(no trailing text, blank lines, or ellipsis after it).Data aggregated by Antalpha AI
Presentation:
- Addresses: short form + full when space allows (e.g.
).0x12ab…89ef (0x12ab…full…) - Numbers: human-readable with sane precision; note unit conversions when helpful (e.g. wei → ETH).
- Missing fields: say “not returned” / “unavailable,” never leave silent gaps.
- Never paste raw JSON blobs, long hex dumps, or full RPC payloads.
Security (production)
- Never print full raw JSON responses or full API bodies.
- Never print
.TOKENVIEW_API_KEY - User-facing content = receipt summary + short errors only.
Versioning
- Skill id:
; this documenttransaction-receipt
. Bumpversion: 1.1.1
and distribution together when you change behavior.version