Observability
DecodeOptions.onEvent is per call. It is not a process-wide listener. Pass a new function on each clearSign, decodeTransaction, or decodeTypedData call.
Events:
| Event | Payload |
|---|---|
decode:start |
kind (transaction, typed-data, batch, user-op) |
decode:end |
kind, durationMs, source, confidence |
registry:fetch |
path, durationMs |
registry:cache-hit |
path |
registry:miss |
chainId, address |
trust:accepted / trust:rejected |
reasons (TrustReasonCode[], snake_case) |
warning:emitted |
warningType from SECURITY_WARNING_TYPES |
The official-registry client emits fetch and cache-hit only when the lookup passes the call’s observer. Two decodes that share a registry do not mix counters. A cache hit on the second call does not emit registry:fetch.
import { clearSign } from '@erc7730/sdk';
const counts = { fetches: 0, hits: 0, accepted: 0, rejected: 0, warnings: 0 };let latencyMs = 0;
await clearSign(tx, { onEvent(event) { if (event.type === 'registry:fetch') counts.fetches += 1; if (event.type === 'registry:cache-hit') counts.hits += 1; if (event.type === 'trust:accepted') counts.accepted += 1; if (event.type === 'trust:rejected') counts.rejected += 1; if (event.type === 'warning:emitted') counts.warnings += 1; if (event.type === 'decode:end') latencyMs = event.durationMs; },});Official-registry hit rate is counts.accepted over finished decodes. Cache hit rate is counts.hits / (counts.hits + counts.fetches) after the indexes are warm. trust:rejected with POLICY_REJECTED in diagnostics is a descriptor the policy refused, which is different from a registry miss.
Batch clearSign emits its own decode:start / decode:end with kind: 'batch', and each call emits the transaction events too.