A contract + off-chain helper system for tracking blockchain events and delivering real-time notifications.
NotifyChain is an open-source event monitoring and notification system designed for smart contracts. It combines on-chain event emission with an off-chain listener service to track contract activity and trigger custom actions such as notifications, webhooks, emails, or integrations with external applications.
The project enables developers to build reactive decentralized applications without continuously polling the blockchain.
- Architecture Overview
- Project Structure
- Event Flow
- Local Development Guide
- Smart Contract Upgrade Guide
- Features
- Use Cases
- Tech Stack
- Contributing
- License
Listener service docs: Notification Failure Recovery — retry lifecycle, configuration, and troubleshooting.
NotifyChain is built from three cooperating layers. On-chain contracts emit events, an off-chain listener turns those events into notifications and a queryable feed, and a dashboard renders that feed for humans. Each layer can be run and developed independently.
| Component | Location | Tech | Responsibility |
|---|---|---|---|
| Smart Contracts | contract/, Documents/Task Bounty/ |
Soroban / Rust | Execute business logic and emit a structured event for every important state change |
| Listener Service | listener/ |
Node.js / TypeScript | Poll the Stellar network for contract events, deduplicate them, push notifications, and expose an HTTP events API |
| Dashboard | dashboard/ |
React + Vite | Fetch the listener's events API and display real-time contract activity |
On-chain Off-chain
┌────────────────────┐ ┌──────────────────────────────┐
│ Soroban Contracts │ │ Listener Service │
│ (TaskBounty, │ emit │ ┌────────────────────────┐ │
│ AutoShare) │ ──────► │ │ EventSubscriber (poll) │ │
│ │ events │ └───────────┬────────────┘ │
└────────────────────┘ │ ▼ │
▲ │ ┌────────────────────────┐ │
│ invoke │ │ Deduplicator + Registry │ │
│ │ └───────────┬────────────┘ │
┌────────────────────┐ │ ┌────────┴────────┐ │
│ Users / dApps │ │ ▼ ▼ │
└────────────────────┘ │ Discord /api/events │
│ webhook HTTP API │
└──────────────────────┬─────────┘
│ fetch
▼
┌────────────────────┐
│ React Dashboard │
└────────────────────┘
A high-level, contributor-facing architecture guide lives in
ARCHITECTURE_OVERVIEW.md. It walks new contributors through the on-chain, off-chain, and dashboard layers, the end-to-end data flow, and links out to every subsystem doc.A more detailed, contract-level architecture write-up lives in
Documents/Task Bounty/ARCHITECTURE.md.
The on-chain layer is the source of truth. Each contract owns its own state and emits typed events (see Event Flow) that the off-chain layer consumes. Two example contracts ship with the project:
A decentralized task and reward board that allows users to:
- Create tasks with escrowed rewards
- Submit work
- Approve/reject submissions
- Raise disputes
- Manage payouts automatically
Key Modules:
types.rs: Data structures and enumsstorage.rs: Storage access patternstask.rs: Task creation and managementsubmission.rs: Work submission handlingdispute.rs: Dispute resolutionevents.rs: Event emission
A subscription and group management contract that allows users to:
- Create sharing groups
- Manage group members
- Handle subscription payments
- Track usage
- Admin management
- Expose contract version for verification
Key Modules:
base/types.rs: Data structuresbase/errors.rs: Error definitionsbase/events.rs: Event emissioninterfaces/autoshare.rs: Interface definitionsautoshare_logic.rs: Core business logicmock_token.rs: Mock token for testingtests/: Comprehensive test suite
Notify-Chain/
├── contract/ # Soroban contract workspace
│ ├── contracts/
│ │ └── hello-world/ # AutoShare contract implementation
│ │ ├── src/
│ │ │ ├── base/
│ │ │ │ ├── errors.rs # Error definitions
│ │ │ │ ├── events.rs # Event types
│ │ │ │ └── types.rs # Data structures
│ │ │ ├── interfaces/
│ │ │ │ └── autoshare.rs # Interfaces
│ │ │ ├── tests/
│ │ │ │ ├── autoshare_test.rs
│ │ │ │ ├── mock_token_test.rs
│ │ │ │ ├── pause_test.rs
│ │ │ │ ├── test_utils.rs
│ │ │ │ └── test_utils_test.rs
│ │ │ ├── autoshare_logic.rs # Core contract logic
│ │ │ ├── lib.rs # Contract entry point
│ │ │ └── mock_token.rs # Mock token for testing
│ │ ├── Cargo.toml
│ │ ├── Makefile
│ │ └── build_log.txt
│ ├── Cargo.toml # Workspace configuration
│ └── README.md
├── listener/ # Off-chain listener service (Node + TS)
│ └── src/
│ ├── api/ # Events HTTP API (/api/events, /health)
│ ├── services/ # Subscriber, deduplicator, Discord notifier
│ ├── store/ # In-memory event registry
│ ├── utils/ # Logging, formatting, helpers
│ └── index.ts # Service entry point
├── dashboard/ # Real-time event dashboard (React + Vite)
│ └── src/
│ ├── components/ # Event list / card / filter UI
│ ├── services/ # Events API client
│ └── store/ # Client-side event store (Zustand)
├── Documents/
│ ├── Task Bounty/ # TaskBounty contract and docs
│ │ ├── src/
│ │ │ ├── dispute.rs
│ │ │ ├── events.rs
│ │ │ ├── lib.rs
│ │ │ ├── storage.rs
│ │ │ ├── submission.rs
│ │ │ ├── task.rs
│ │ │ ├── test.rs
│ │ │ └── types.rs
│ │ ├── API.md
│ │ ├── ARCHITECTURE.md
│ │ ├── CONTRIBUTING.md
│ │ ├── PROJECT_CHECKLIST.md
│ │ ├── PROJECT_OVERVIEW.md
│ │ ├── README.md
│ │ ├── SETUP.md
│ │ ├── SUMMARY.md
│ │ ├── WORKFLOWS.md
│ │ └── Cargo.toml
│ └── Stellar-save/
├── .vscode/
│ └── settings.json
├── README.md # This file
├── ARCHITECTURE_OVERVIEW.md # High-level architecture guide (issue #137)
└── .gitignore
This is how a single on-chain action becomes a delivered notification:
1. A user invokes a contract function (e.g. create_task)
↓
2. The contract updates state and emits a typed event
↓
3. The listener's EventSubscriber polls the Stellar RPC and picks up the event
↓
4. The event is validated, parsed, and recorded in the in-memory event registry
↓
5. The deduplicator drops events already seen (by contract + event id)
↓
6. A Discord notification is sent (if a webhook is configured)
↓
7. The dashboard fetches GET /api/events and renders the new activity
Key pieces of the off-chain pipeline:
EventSubscriber(listener/src/services/event-subscriber.ts) polls the configured contracts on an interval and reconnects on failure.NotificationDeduplicator(listener/src/services/notification-deduplicator.ts) prevents the same event from being notified twice.DiscordNotificationService(listener/src/services/discord-notification.ts) formats and delivers notifications.- Events API (
listener/src/api/events-server.ts) exposesGET /api/eventsfor the dashboard andGET /healthfor monitoring.
The contract events that drive this flow are listed below.
| Event | Trigger | Data Included |
|---|---|---|
TaskCreated |
When a new task is created | Task ID, Poster address, Title, Reward, Deadline |
WorkSubmitted |
When work is submitted for a task | Task ID, Submission ID, Contributor, Work URL |
SubmissionApproved |
When a submission is approved | Task ID, Submission ID, Contributor, Reward |
SubmissionRejected |
When a submission is rejected | Task ID, Submission ID, Contributor |
TaskCancelled |
When a task is cancelled | Task ID, Poster address |
DisputeRaised |
When a dispute is raised | Task ID, Submission ID, Raiser, Reason |
1. Poster calls create_task()
↓
2. Contract escrows reward tokens
↓
3. Contract emits TaskCreated event
↓
4. Contributor calls submit_work()
↓
5. Contract emits WorkSubmitted event
↓
6. Poster calls approve_submission()
↓
7. Contract transfers reward to contributor
↓
8. Contract emits SubmissionApproved event
| Event | Trigger | Data Included |
|---|---|---|
AutoshareCreated |
When a new AutoShare group is created | Creator address, Group ID |
AutoshareUpdated |
When a group is updated | Updater address, Group ID |
ContractPaused |
When the contract is paused | N/A |
ContractUnpaused |
When the contract is unpaused | N/A |
GroupDeactivated |
When a group is deactivated | Creator address, Group ID |
GroupActivated |
When a group is activated | Creator address, Group ID |
AdminTransferred |
When admin rights are transferred | Old admin, New admin |
Withdrawal |
When tokens are withdrawn | Token address, Recipient, Amount |
Before getting started, make sure you have the following installed:
- Rust: The programming language used for Soroban contracts
- WebAssembly Target: For compiling to Wasm
- Stellar CLI: For interacting with Soroban contracts
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source $HOME/.cargo/envVerify installation:
rustc --version
cargo --versionrustup target add wasm32-unknown-unknowncargo install --locked stellar-cli --features optVerify installation:
stellar --version-
Clone the repository:
git clone https://github.com/your-org/notify-chain.git cd notify-chain -
Building the AutoShare contract:
cd contract stellar contract build -
Running tests for AutoShare contract:
cd contracts/hello-world cargo test
-
Building the TaskBounty contract:
cd ../../Documents/Task\ Bounty cargo build --target wasm32-unknown-unknown --release # Or using Stellar CLI: stellar contract build
-
Running tests for TaskBounty contract:
cargo test
stellar keys generate test-user --network testnetstellar keys fund test-user --network testnetcd contract/contracts/hello-world
stellar contract deploy \
--wasm target/wasm32-unknown-unknown/release/hello_world.wasm \
--source test-user \
--network testnetstellar contract invoke \
--id <CONTRACT_ID> \
--source test-user \
--network testnet \
-- \
initialize_admin \
--admin <ADMIN_ADDRESS>| Command | Purpose |
|---|---|
stellar contract build |
Build a contract |
cargo test |
Run tests |
stellar contract deploy |
Deploy a contract |
stellar contract invoke |
Call a contract function |
stellar contract optimize |
Optimize contract for deployment |
stellar keys list |
List your identities |
Install the following extensions for a smooth development experience:
- rust-analyzer - Rust language support
- CodeLLDB - Debugger
- Better TOML - TOML file support
Add this to .vscode/settings.json:
{
"rust-analyzer.cargo.target": "wasm32-unknown-unknown",
"rust-analyzer.checkOnSave.allTargets": false
}Before changing contract storage, public methods, event schemas, authorization rules, or deployment artifacts, read the Smart Contract Upgrade Guide. It documents the recommended upgrade workflow, prerequisites, testnet verification steps, rollback procedures, risk checklist, and PR template for NotifyChain contract changes.
- 📡 Real-time blockchain event monitoring
- 🔗 Smart contract event emission
- ⚡ Off-chain listener service
- 🔔 Custom notification triggers
- 🌐 Webhook support for external integrations
- 📝 Event logging and processing
- 🛠️ Easy integration into existing dApps
- 🔒 Trustless and transparent event tracking
- Task completion notifications
- Escrow payment updates
- NFT mint alerts
- DAO proposal events
- Bounty submissions
- Token transfers
- Marketplace purchases
- Governance voting updates
- DeFi protocol monitoring
- Custom application events
- Soroban (Stellar smart contracts)
- Rust
- Node.js
- TypeScript
- Stellar SDK
- React + Vite (dashboard)
- Discord (implemented)
- Email, Telegram, Slack, Webhooks, Push Notifications (planned)
Contributions are welcome! Please follow these steps:
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to your branch
- Open a Pull Request
Please follow the project's coding standards and include tests where applicable.
For more detailed contribution guidelines, check:
Documents/Task Bounty/CONTRIBUTING.md
This project is licensed under the MIT License.
NotifyChain is built to simplify event-driven blockchain development by bridging smart contract events with off-chain automation and notification systems.
To run the staging environment locally:
- Export environment variables:
export $(cat listener/.env.staging | xargs) - Build and run listener:
cd listener && npm ci && npm run build && npm start - Run health check:
./scripts/health-check.sh