Skip to main content
Every sign_transaction and send_transaction operation produces an audit receipt appended to a local JSONL log. Receipts are linked by a SHA-256 hash chain for tamper detection.

Location

SettingDefaultOverride
Audit file~/.walletsuite/audit-trail.jsonlWALLETSUITE_AUDIT_PATH env var
The file is append-only and local-only. It does not support concurrent writers.

Receipt Format

Each line is a JSON object containing:
FieldDescription
receiptIdUnique receipt identifier
timestampISO 8601 timestamp
toolsign_transaction or send_transaction
walletNameOWS wallet used for signing
chainChain ID (e.g., eip155:1, tron:mainnet)
txDigestTruncated transaction hex (first 8 + last 8 chars)
txHashOn-chain transaction hash (if broadcast succeeded)
approvalStatusconfirmed, missing, or not_required
counterpartyCheckCounterparty screening result. An object, not a scalar: { status: "not_performed" }, { status: "performed", provider?, result: "clear" | "flagged", details? }, or { status: "failed", provider?, errorCode?, errorMessage? }
policyPolicy evaluation snapshot: result (allow/deny), matchedRules, policyIds, denyReason
outcomesuccess or error
errorCodeError code (if outcome is error)
errorMessageError message (if outcome is error)
elapsedMsOperation duration in milliseconds
contentHashSHA-256 hash of the receipt content (excluding chain fields)
prevHashPrevious receipt’s entryHash (forms the chain)
entryHashSHA-256 over prevHash + ":" + contentHash when prevHash exists; SHA-256 over contentHash alone for the first receipt. The chain link

Hash Chain

Each receipt has two hashes: contentHash (SHA-256 of the receipt data) and entryHash (SHA-256 that links the receipt to the previous one). The first receipt’s entryHash is just the SHA-256 of its contentHash. Every subsequent receipt’s entryHash is SHA-256 of prevHash + ":" + contentHashprevHash first, a literal : separator, then the current receipt’s contentHash. Tampering with any entry invalidates every entry after it.
Receipt 1: contentHash = SHA-256(receipt_1_data)
            entryHash  = SHA-256(contentHash)

Receipt 2: contentHash = SHA-256(receipt_2_data)
            entryHash  = SHA-256(receipt_1.entryHash + ":" + contentHash)

Receipt 3: contentHash = SHA-256(receipt_3_data)
            entryHash  = SHA-256(receipt_2.entryHash + ":" + contentHash)
To verify integrity, walk the chain and confirm each receipt’s prevHash equals the preceding receipt’s entryHash, then recompute entryHash using the formula above.

Secret Redaction

The audit trail automatically redacts sensitive patterns before writing:
  • API keys and bearer tokens
  • Mnemonics and private keys
  • GitHub and AWS credentials
  • Multiple patterns matched in a single compiled pass
Transaction hex is truncated to first 8 + last 8 characters to prevent key material leakage from serialized payloads.

Querying

The file is newline-delimited JSON. Query with standard tools:
# Last 10 entries
tail -10 ~/.walletsuite/audit-trail.jsonl | jq .

# All denied operations
cat ~/.walletsuite/audit-trail.jsonl | jq 'select(.policy.result == "deny")'

# All successful broadcasts
cat ~/.walletsuite/audit-trail.jsonl | jq 'select(.tool == "send_transaction" and .outcome == "success")'

# Signing activity for a specific wallet
cat ~/.walletsuite/audit-trail.jsonl | jq 'select(.walletName == "treasury")'

# Counterparty screening that ran and flagged a recipient
# Note: counterpartyCheck is an object — filter on the nested .status / .result fields.
cat ~/.walletsuite/audit-trail.jsonl | jq 'select(.counterpartyCheck.status == "performed" and .counterpartyCheck.result == "flagged")'

SIEM Integration

Export the JSONL file to your SIEM or log aggregation system:
  • Filebeat / Fluentd: Tail the JSONL file and forward to Elasticsearch, Datadog, or Splunk
  • CloudWatch Logs: For Docker deployments, mount the audit path and ship with the CloudWatch agent
  • S3 archival: Periodically copy the file to S3 for long-term retention
The structured JSON format is compatible with any log ingestion pipeline that supports JSONL.

Large File Handling

Within a running server process, the previous receipt’s entryHash is cached in memory — each append links to the cached hash, so the chain stays intact for the lifetime of that process regardless of file size. The ~100 MB threshold only matters at startup (or the first append after a process restart), when the server bootstraps the cache by reading back from disk. If the existing audit file exceeds ~100 MB at that moment, the server skips reading the previous hash to avoid blocking the Node.js event loop, logs audit_prev_hash_skipped_large_file, and the next receipt is written without a prevHash link. Subsequent receipts in the same process chain normally. For high-volume deployments, rotate the audit file off-process (archive and truncate) before it crosses the threshold, or restart the server behind a rotation to keep the bootstrap path cheap.