Rule-based transaction filtering for Cardano. Connects to Ogmios, applies configurable rules, and emits CloudEvents via Dapr pub/sub.
- Real-time chain sync via Ogmios
- Pluggable rule engine with built-in rules
- CloudEvents 1.0 output with Cardano extensions
- Dual delivery: HTTP (Dapr pub/sub) and gRPC server-streaming
- At-least-once delivery with configurable retry and dead letter queues
- Dapr state store checkpointing with ETag concurrency
- OpenAPI/Swagger API documentation
- SDK-less event consumption (any language)
- React event viewer UI with real-time SSE dashboard and rule filter selector
- Getting Started - Community onboarding (run, extend, adopt)
- Architecture Overview - System design and components
- Event Schema - CloudEvents specification
- Integration Guide - Building custom rules
- UI Consumer Guide - Building and extending the React dashboard
- Benchmark Results - Performance and delivery guarantees
- OpenAPI Spec - API specification
- Example Configurations - Governance, treasury, and metadata filters
- Contributing - Development guidelines
- Milestone 1 — Core Filtering Engine & Event Emission
- Milestone 2 — Event Delivery Layer
- Milestone 3 — Interactive Consumer & Visualisation
- Milestone 4 — Finalisation, Documentation & Community Release
- Close-out Report
- Test Report
The repository separates backend and frontend into independently deployable layers:
/backend → src/ # .NET event delivery layer (Worker, Engine, Domain)
/ui → tools/event-viewer/ # React interactive consumer & visualisation
src/
├── BlockchainEvents.Domain/ # Models, abstractions, events (NuGet)
├── BlockchainEvents.Engine/ # Rule engine and implementations (NuGet)
└── BlockchainEvents.Worker/ # .NET Worker service (HTTP + gRPC + SSE)
examples/
├── governance/ # CIP-1694 governance filter profile
├── treasury/ # Treasury withdrawal filter profile
├── metadata/ # CIP-20 metadata filter profile
└── run-example.sh # Launch stack with an example config
tools/
├── event-viewer/ # React 19 dashboard (SSE consumer)
├── BlockchainEvents.DemoSubscriber/ # .NET pub/sub consumer demo
└── milestone-2-demo.sh # Milestone 2 guided demo
protos/
└── blockchain_events.proto # gRPC service definitions
tests/
└── BlockchainEvents.Tests/ # Unit tests
docs/
├── getting-started.md # Community onboarding
├── architecture.md # System architecture
├── event-schema.md # Event schema specification
├── integration-guide.md # Custom rule development
├── ui-consumer-guide.md # UI setup, architecture, extension guide
├── benchmarks.md # Performance benchmarks
└── openapi.json # OpenAPI 3.0 spec
| Rule | Purpose |
|---|---|
| AddressMatch | Filter by wallet addresses or prefixes |
| PolicyIdAsset | Filter by policy IDs and asset names |
| MetadataKeyValue | Filter by metadata labels and patterns |
| GovernanceTreasury | Filter governance actions, votes, treasury |
| AllTransactions | Match all transactions (testing/capture) |
Rules are configured via appsettings.json or have sensible defaults.
Minimal config (appsettings.json):
{
"BlockchainEvents": {
"Network": "preprod",
"StateStoreName": "statestore",
"PubSubName": "pubsub",
"TopicName": "blockchain-events",
"CheckpointKey": "sync-checkpoint"
},
"Ogmios": {
"Connection": {
"Host": "localhost",
"Port": 1337
}
}
}- .NET 10 SDK
- Docker (for full stack)
- Ogmios running locally (port 1337)
./setup.sh # adds blockchain.local to /etc/hosts — use instead of localhostdocker compose up --build
# Multi-stage Dockerfiles publish in-container — no host publish/ directory required.
# View traces at http://localhost:4004./examples/run-example.sh governance
./examples/run-example.sh treasury
./examples/run-example.sh metadataOr: WORKER_APPSETTINGS=./examples/metadata/appsettings.json docker compose up --build
Latest community release: v1.0.1
| Artifact | Location |
|---|---|
| Worker image | ghcr.io/itsdaveb/ogmiosdotnet.blockchainevents:1.0.1 (GHCR) |
| Event viewer image | ghcr.io/itsdaveb/ogmiosdotnet.blockchainevents/event-viewer:1.0.1 (GHCR) |
| NuGet Domain | OgmiosDotnet.BlockchainEvents.Domain 1.0.1 |
| NuGet Engine | OgmiosDotnet.BlockchainEvents.Engine 1.0.1 |
Subsequent v* tags publish the same artifacts via GHCR, nuget.org (Trusted Publishing), GitHub Packages, and a GitHub Release.
# Terminal 1: Start infrastructure
docker compose up redis placement zipkin
# Terminal 2: Run with Dapr CLI
dapr run --app-id blockchain-events \
--app-port 4000 \
--resources-path ./dapr/components \
--config ./dapr/config/config.yaml \
-- dotnet run --project src/BlockchainEvents.Workerdotnet test# Install grpcurl
brew install grpcurl
# Subscribe to all events (streams until Ctrl+C)
grpcurl -plaintext -import-path . -proto protos/blockchain_events.proto \
-d '{}' localhost:4010 blockchain_events.BlockchainEventService/Subscribe
# Subscribe to address-match events only
grpcurl -plaintext -import-path . -proto protos/blockchain_events.proto \
-d '{"rule_filter": "address-match"}' localhost:4010 blockchain_events.BlockchainEventService/Subscribe# Milestone 2: event delivery layer (AC-1 through AC-3)
./tools/milestone-2-demo.shdocker compose up --build
# Open http://localhost:4020 (all rules)
# http://localhost:4021 (metadata filter)
# http://localhost:4022 (governance filter)
# http://localhost:4023 (address match filter)See docs/ui-consumer-guide.md for setup, architecture, and extension guide.
public class HighFeeRule(IOptions<HighFeeOptions> options) : TransactionRuleBase
{
public override string Id => "high-fee";
public override string Name => "High Fee Rule";
public override string Description => "Matches high-fee transactions";
public override bool IsEnabled => options.Value.Enabled;
public override bool IsMatch(TransactionData tx, RuleContext ctx)
=> tx.Fee > options.Value.ThresholdLovelace;
public override RuleMatchResult Evaluate(TransactionData tx, RuleContext ctx)
=> new(Id, Name, new Dictionary<string, object> { ["fee"] = tx.Fee });
}
// Register: services.AddSingleton<ITransactionRule, HighFeeRule>();See docs/integration-guide.md for detailed examples.
Events are emitted as CloudEvents 1.0 with Cardano extensions:
{
"specversion": "1.0",
"id": "tx-abc123-address-match-1705312200000",
"source": "cardano://mainnet/slot/115545883/block/4e58bb36...",
"type": "io.cardano.transaction.address-match",
"cardanoslot": 115545883,
"cardanonetwork": "mainnet",
"data": {
"transactionId": "abc123...",
"ruleId": "address-match",
"matchedCriteria": { ... }
}
}See docs/event-schema.md for complete specification.
See CONTRIBUTING.md for development setup and guidelines.