CAP plugin for monitoring the Cardano blockchain. Watches addresses, payment credentials, and minting policies; emits events with rich UTxO payloads (assets, inline datums, reference scripts) and persists them for replay.
npm add @odatano/watchpackage.json:
{
"cds": {
"requires": {
"watch": {
"network": "preview",
"blockfrostApiKey": "preview_YOUR_KEY",
"autoStart": true
}
}
}
}Credential and policy watching are off by default — opt in via credentialPolling / policyPolling. Credential watching also needs a (free-tier-OK) Koios endpoint. See Quick Start for the full config.
To keep the API key out of package.json, leave the field unset and export the env var instead — the plugin picks it up as a fallback:
{ "cds": { "requires": { "watch": { "network": "preview" } } } }export BLOCKFROST_API_KEY=preview_YOUR_KEYOther recognized env vars: BLOCKFROST_CUSTOM_BACKEND, KOIOS_API_KEY, OGMIOS_URL, WATCHER_BACKEND. cds.env.requires.watch.<field> always wins when set.
Polling burns through the Blockfrost free-tier daily quota quickly. To route the SDK at a self-hosted Blockfrost-compatible endpoint instead, set blockfrostCustomBackend (and drop blockfrostApiKey):
{
"cds": {
"requires": {
"watch": {
"network": "mainnet",
"blockfrostCustomBackend": "http://localhost:3100/api/v0",
"credentialPolling": { "enabled": true, "interval": 30 }
}
}
}
}http://localhost:3100/api/v0 is the default for Dolos's MiniBF. Equivalent env var: BLOCKFROST_CUSTOM_BACKEND. Public Blockfrost stays the default when this field is unset.
import type {
NewTransactionsEvent,
CredentialNewTransactionsEvent,
PolicyAssetMintedEvent,
} from "@odatano/watch";
cds.on("cardano.newTransactions", async (e: NewTransactionsEvent) => {
// e.address, e.tag?, e.transactions[], e.utxosCreated[], e.utxosSpent[]
for (const utxo of e.utxosCreated) {
if (utxo.inlineDatumHex) await applyDatum(utxo.inlineDatumHex);
}
});
cds.on("cardano.credential.newTransactions", async (e: CredentialNewTransactionsEvent) => { /* ... */ });
cds.on("cardano.policy.assetMinted", async (e: PolicyAssetMintedEvent) => { /* ... */ });Other emitted events: cardano.policy.assetBurned, and (Phase 2 / Ogmios only) cardano.rollback.
Read Event Delivery Semantics before building stateful consumers — there are guarantees we don't make (no cross-handler ordering, no retry, no backpressure) and a checklist of patterns to follow.
POST /odata/v4/cardano-watcher-admin/addWatchedAddress
Content-Type: application/json
{
"address": "addr_test1...",
"tag": "my-pool",
"includesAssetsJson": "[{\"policyId\":\"...\",\"assetNameHex\":\"\"}]",
"coalesceMs": 2000
}Plus addWatchedCredential, addWatchedPolicy, removeWatched*. Optional fields:
tag— echoed back on each emit for dispatch routing.includesAssetsJson— asset allowlist; non-matching txs are skipped.coalesceMs— batch bus emits into one event per window with cumulative deltas (1 – 300_000).
POST /odata/v4/cardano-watcher-admin/getEventsSince
Content-Type: application/json
{ "scope": "address", "key": "addr_test1...", "fromBlock": 12345 }Returns persisted BlockchainEvent rows ordered by blockHeight asc. Use the last returned blockHeight as the next call's fromBlock for cursor pagination.
Set backend: 'ogmios' and ogmiosUrl: 'ws://localhost:1337' to switch from polling to a chainSync stream with native rollback signal. Backfill from Blockfrost runs once per new watch. See Architecture → Phase 2 for caveats.
