@odatano/watch
v0.1.2
Published
CAP Plugin for deterministic monitoring of Cardano blockchain events and transactions (via Blockfrost)
Downloads
280
Maintainers
Readme
ODATANO-WATCH - CAP-based Cardano Blockchain Monitoring Plugin
A CAP (Cloud Application Programming Model) plugin for monitoring the Cardano blockchain. Built as a fully integrated plugin, it can be seamlessly integrated into existing CAP projects to provide blockchain functionalities such as address monitoring, transaction tracking, and event management.
📚 Documentation: Quick Start | Setup Guide | Architecture
Features
✅ Plug & Play Integration: Automatic CDS plugin registration
✅ TypeScript First: Fully type-safe with complete type definitions
✅ Address Monitoring: Monitor Cardano addresses for new transactions
✅ Transaction Tracking: Track submitted transactions and their confirmations
✅ Multi-Path Polling: Independent polling intervals for different monitoring types
✅ Event-based Architecture: Different events for different blockchain activities
✅ OData Admin Service: Complete REST/OData API for management and monitoring
✅ Multi-Network Support: Support for mainnet, preview, and preprod
✅ Production Ready: Comprehensive error handling, logging, and validation
✅ Extensible: Ready for Smart Contracts, NFTs, and custom events
Installation
npm add @odatano/watchQuick Start
1. Configure the Plugin
Add the configuration to your CAP project's package.json:
{
"cds": {
"requires": {
"watch": {
"network": "preview",
"blockfrostApiKey": "previewABC123...",
"autoStart": true,
"addressPolling": {
"enabled": true,
"interval": 30
},
"transactionPolling": {
"enabled": true,
"interval": 60
}
}
}
}
}2. Automatic Initialization
The plugin is automatically loaded as a CDS plugin. No manual initialization required!
3. Use Events
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:
Entities
GET /cardano-watcher-admin/WatchedAddresses
GET /cardano-watcher-admin/TransactionSubmissions
GET /cardano-watcher-admin/BlockchainEvents
GET /cardano-watcher-admin/WatcherConfigsControl Actions
Watcher Control
POST /cardano-watcher-admin/startWatcher # Start all polling paths
POST /cardano-watcher-admin/stopWatcher # Stop all polling paths
POST /cardano-watcher-admin/getWatcherStatus # Get statusAddress Monitoring
POST /cardano-watcher-admin/addWatchedAddress
Content-Type: application/json
{
"address": "addr_test1qrgfq5jeznaehnf4zs02laas2juuuyzlz48tkue50luuws2nrznmesueg7drstsqaaenq6qpcnvqvn0kessd9fw2wxys6tv622",
"description": "My Wallet",
"network": "preview"
}POST /cardano-watcher-admin/removeWatchedAddress
Content-Type: application/json
{
"address": "addr_test1qrgfq5jeznaehnf4zs02laas2juuuyzlz48tkue50luuws2nrznmesueg7drstsqaaenq6qpcnvqvn0kessd9fw2wxys6tv622"
}Transaction Tracking
POST /cardano-watcher-admin/addWatchedTransaction
Content-Type: application/json
{
"txHash": "cade0ed879a9ea5dd65f13be98581d476b0e77946c9c11123832225a7de55e28",
"description": "Payment to supplier",
"network": "preview"
}POST /cardano-watcher-admin/removeWatchedTransaction
Content-Type: application/json
{
"txHash": "cade0ed879a9ea5dd65f13be98581d476b0e77946c9c11123832225a7de55e28"
}Programmatic Usage
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
Address Activity Event
Emitted when new transactions are detected for a watched address.
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);
}
});Transaction Confirmation Event
Emitted when a submitted transaction is confirmed in the blockchain.
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:
WatchedAddress
Stores addresses to monitor.
entity WatchedAddress {
key address: Bech32;
description: String(500);
active: Boolean;
lastCheckedBlock: Integer64;
network: String(20);
events: Composition of many BlockchainEvent;
hasEvents: Boolean;
}TransactionSubmission
Tracks submitted transactions.
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;
}BlockchainEvent
Stores all detected blockchain events.
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;
}Transaction
Detailed transaction information.
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:
Address Polling (Default: 30s)
- Monitors all active
WatchedAddressentries - Fetches new transactions from the blockchain
- Stores detected transactions in
TransactionandBlockchainEvent - Emits
cardano.newTransactionsevent
Transaction Polling (Default: 60s)
- Monitors all active
TransactionSubmissionentries - Checks if submitted transactions are in the blockchain
- Updates status from PENDING to CONFIRMED
- Emits
cardano.transactionConfirmedevent
Both paths can be controlled independently:
await cardanoWatcher.startAddressPolling();
await cardanoWatcher.stopTransactionPolling();Development
Project Structure
├── 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.jsonBuild
npm run build # Compile TypeScript
npm run build:watch # Watch mode for developmentTests
npm test # Run all tests
npm run test:watch # Watch mode for tests
npm run test:coverage # Run tests with coverage reportCode Quality
npm run lint # Run ESLint
npm run format # Prettier code formattingConfiguration Options
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
};
}License
Apache-2.0
Support
For questions or issues, please create an Issue.
