CAP Plugin for deterministic monitoring of Cardano blockchain events and transactions (via Blockfrost)
npm install @odatano/watchbash
npm add @odatano/watch
`
Quick Start
$3
Add the configuration to your CAP project's package.json:
`json
{
"cds": {
"requires": {
"watch": {
"network": "preview",
"blockfrostApiKey": "previewABC123...",
"autoStart": true,
"addressPolling": {
"enabled": true,
"interval": 30
},
"transactionPolling": {
"enabled": true,
"interval": 60
}
}
}
}
}
`
$3
The plugin is automatically loaded as a CDS plugin. No manual initialization required!
$3
`typescript
import type {
NewTransactionsEvent,
TxConfirmedEvent
} from "@odatano/watch";
// Address Monitoring: React to new transactions
cds.on("cardano.newTransactions", async (data: NewTransactionsEvent) => {
console.log(${data.count} new transactions for ${data.address});
for (const txHash of data.transactions) {
await processPayment(txHash);
}
});
// Transaction Tracking: React to transaction confirmations
cds.on("cardano.transactionConfirmed", async (data: TxConfirmedEvent) => {
console.log(TX ${data.txHash} confirmed in block ${data.blockHeight});
await markOrderAsCompleted(data.txHash);
});
`
Admin Service API
The plugin provides a complete OData/REST Admin Service:
$3
`http
GET /cardano-watcher-admin/WatchedAddresses
GET /cardano-watcher-admin/TransactionSubmissions
GET /cardano-watcher-admin/BlockchainEvents
GET /cardano-watcher-admin/WatcherConfigs
`
$3
Watcher Control
`http
POST /cardano-watcher-admin/startWatcher # Start all polling paths
POST /cardano-watcher-admin/stopWatcher # Stop all polling paths
POST /cardano-watcher-admin/getWatcherStatus # Get status
`
Address Monitoring
`http
POST /cardano-watcher-admin/addWatchedAddress
Content-Type: application/json
{
"address": "addr_test1qrgfq5jeznaehnf4zs02laas2juuuyzlz48tkue50luuws2nrznmesueg7drstsqaaenq6qpcnvqvn0kessd9fw2wxys6tv622",
"description": "My Wallet",
"network": "preview"
}
`
`http
POST /cardano-watcher-admin/removeWatchedAddress
Content-Type: application/json
{
"address": "addr_test1qrgfq5jeznaehnf4zs02laas2juuuyzlz48tkue50luuws2nrznmesueg7drstsqaaenq6qpcnvqvn0kessd9fw2wxys6tv622"
}
`
Transaction Tracking
`http
POST /cardano-watcher-admin/addWatchedTransaction
Content-Type: application/json
{
"txHash": "cade0ed879a9ea5dd65f13be98581d476b0e77946c9c11123832225a7de55e28",
"description": "Payment to supplier",
"network": "preview"
}
`
`http
POST /cardano-watcher-admin/removeWatchedTransaction
Content-Type: application/json
{
"txHash": "cade0ed879a9ea5dd65f13be98581d476b0e77946c9c11123832225a7de55e28"
}
`
Programmatic Usage
`typescript
import cardanoWatcher from "@odatano/watch";
// Start/stop all polling paths
await cardanoWatcher.start();
await cardanoWatcher.stop();
// Get status
const status = cardanoWatcher.getStatus();
const config = cardanoWatcher.config();
`
Event Types
$3
Emitted when new transactions are detected for a watched address.
`typescript
import type { NewTransactionsEvent } from "@odatano/watch";
cds.on("cardano.newTransactions", async (event: NewTransactionsEvent) => {
console.log(Address: ${event.address});
console.log(Count: ${event.count});
console.log(TxHashes: ${event.transactions.join(", ")});
// Process each transaction
for (const txHash of event.transactions) {
await processPayment(txHash);
}
});
`
$3
Emitted when a submitted transaction is confirmed in the blockchain.
`typescript
import type { TxConfirmedEvent } from "@odatano/watch";
cds.on("cardano.transactionConfirmed", async (event: TxConfirmedEvent) => {
console.log(TX ${event.txHash} confirmed!);
console.log(Block: ${event.blockHeight});
console.log(Confirmations: ${event.confirmations});
// Mark order as completed
await markOrderAsCompleted(event.txHash);
});
`
Data Model
The plugin provides the following entities:
$3
Stores addresses to monitor.
`cds
entity WatchedAddress {
key address: Bech32;
description: String(500);
active: Boolean;
lastCheckedBlock: Integer64;
network: String(20);
events: Composition of many BlockchainEvent;
hasEvents: Boolean;
}
`
$3
Tracks submitted transactions.
`cds
entity TransactionSubmission {
key txHash: Blake2b256;
description: String(500);
active: Boolean;
currentStatus: String(20); // PENDING, CONFIRMED, FAILED
confirmations: Integer;
network: String(20);
events: Composition of many BlockchainEvent;
hasEvents: Boolean;
}
`
$3
Stores all detected blockchain events.
`cds
entity BlockchainEvent {
key id: UUID;
type: String(50); // TX_CONFIRMED, ADDRESS_ACTIVITY, etc.
description: String(500);
blockHeight: Integer64;
blockHash: Blake2b256;
txHash: Blake2b256;
address: Association to WatchedAddress;
submission: Association to TransactionSubmission;
payload: LargeString;
processed: Boolean;
processedAt: Timestamp;
error: LargeString;
network: String(20);
createdAt: Timestamp;
}
`
$3
Detailed transaction information.
`cds
entity Transaction {
key ID: UUID;
txHash: Blake2b256;
blockNumber: Integer64;
blockHash: Blake2b256;
sender: Bech32;
receiver: Bech32;
amount: Lovelace;
fee: Lovelace;
metadata: LargeString;
assets: LargeString;
status: String(20);
network: String(20);
inMempool: Boolean;
mempoolEnteredAt: Timestamp;
confirmedAt: Timestamp;
createdAt: Timestamp;
}
`
Polling Mechanism
The plugin uses two independent polling paths:
$3
- Monitors all active WatchedAddress entries
- Fetches new transactions from the blockchain
- Stores detected transactions in Transaction and BlockchainEvent
- Emits cardano.newTransactions event
$3
- Monitors all active TransactionSubmission entries
- Checks if submitted transactions are in the blockchain
- Updates status from PENDING to CONFIRMED
- Emits cardano.transactionConfirmed event
Both paths can be controlled independently:
`typescript
await cardanoWatcher.startAddressPolling();
await cardanoWatcher.stopTransactionPolling();
`
Development
$3
`
āāā src/ # TypeScript source code
ā āāā index.ts # Main Plugin Module
ā āāā config.ts # Configuration Management
ā āāā watcher.ts # Blockchain Watcher Logic
ā āāā blockfrost.ts # Blockfrost API Integration
ā āāā plugin.ts # Plugin Implementation
āāā srv/ # Service Definitions & Implementations
ā āāā admin-service.cds # Admin Service Definition
ā āāā admin-service.ts # Admin Service Implementation
ā āāā utils/ # Service Utilities
ā āāā backend-request-handler.ts
ā āāā error-codes.ts
ā āāā errors.ts
ā āāā validators.ts
āāā db/ # CDS Data Model
ā āāā schema.cds # Entity Definitions
āāā @cds-models/ # Generated Type Definitions
ā āāā index.ts
ā āāā CardanoWatcherAdminService/
āāā docs/ # Documentation
ā āāā QUICKSTART.md
ā āāā SETUP.md
ā āāā ARCHITECTURE.md
āāā test/ # Tests
ā āāā unit/
ā āāā integration/
āāā cds-plugin.js # CDS Plugin Entry Point
āāā package.json
āāā tsconfig.json
`
$3
`bash
npm run build # Compile TypeScript
npm run build:watch # Watch mode for development
`
$3
`bash
npm test # Run all tests
npm run test:watch # Watch mode for tests
npm run test:coverage # Run tests with coverage report
`
$3
`bash
npm run lint # Run ESLint
npm run format # Prettier code formatting
`
Configuration Options
`typescript
interface CardanoWatcherConfig {
network?: "mainnet" | "preview" | "preprod";
blockfrostApiKey?: string;
autoStart?: boolean;
maxRetries?: number;
retryDelay?: number;
addressPolling?: {
enabled: boolean;
interval: number; // in seconds
};
transactionPolling?: {
enabled: boolean;
interval: number; // in seconds
};
}
``