A production-oriented Telegram bot for tracking Kaspa wallets, confirmed solo-mining rewards, wallet balances, BlockDAG/network metrics, and mining alerts.
Kaspa Pulse is a Rust application that connects to a Kaspa node through wRPC/WebSocket and stores wallet, reward, deduplication, event, and delivery state in PostgreSQL.
The repository intentionally uses a small auditable stack. It does not add Node.js, npm, TypeScript, ESLint, or a JavaScript web framework because the application does not contain a JavaScript/TypeScript runtime that needs them.
Telegram user
β
Command / wallet input
β
Validation + actor-scoped rate limits
β
PostgreSQL wallet state
β
UTXO monitor
β
Reward confirmation gate
β
DAG analysis
β
Event log + wallet-scoped deduplication
β
telegram_delivery_queue
β
Telegram delivery worker
- Rust 1.97.1, pinned in
rust-toolchain.toml. - Rust Edition 2024.
- PostgreSQL 18 validation baseline with PostgreSQL-only SQLx 0.9 feature selection.
- Teloxide 0.17 and Axum 0.8.
- Reqwest 0.13 with Rustls.
rusty-kaspadependencies pinned to the approvedv2.0.1Git tag.- Debian 13 (Trixie) production container.
- Non-root container runtime using UID/GID
10001.
The crate has publish = false to prevent accidental publication to crates.io.
- Add, remove, and list Kaspa wallets.
- Track wallet balances and UTXOs.
- Detect coinbase mining rewards.
- Wait for the configured reward-confirmation threshold.
- Analyze BlockDAG acceptance.
- Persist mined-block history.
- Apply wallet-scoped deduplication.
- Queue Telegram delivery in PostgreSQL with retry/backoff state.
- Private-chat admin authorization.
- Actor-scoped command and callback rate limits.
- One-time CSPRNG confirmation nonces for sensitive admin actions.
- SHA-256-indexed confirmation state.
- Fail-closed behavior on sensitive database paths.
- Privacy-aware logging and input limits.
- Local health, readiness, and Prometheus-style metrics endpoints.
- Graceful shutdown handling.
- Panic/restart marker support.
/pause = pause live monitoring
/mute_alerts = keep monitoring but suppress outgoing mining alerts
- Rust 1.97.1.
- PostgreSQL 18 recommended.
- A reachable Kaspa wRPC endpoint.
- A Telegram bot token.
- Docker/Compose only for container deployment.
Use the repository-pinned Rust toolchain rather than relying on a machine-global default.
Copy .env.example to .env and replace every placeholder. Never commit .env.
Minimum production configuration:
BOT_TOKEN=PUT_YOUR_TELEGRAM_BOT_TOKEN_HERE
ADMIN_USER_ID=PUT_YOUR_TELEGRAM_ADMIN_USER_ID_HERE
ADMIN_CHAT_ID=PUT_THE_SAME_PRIVATE_CHAT_ID_HERE
NODE_URL_01=wss://your-kaspa-node.example.com/json
DATABASE_URL=postgres://kaspa_pulse_app:PUT_APP_PASSWORD_HERE@127.0.0.1:5433/kaspa_dev?sslmode=disable
APP_ENV=production
RUST_LOG=info
SQLX_OFFLINE=true
ALLOW_RUNTIME_SCHEMA_ENSURE=false
ENABLE_TELEGRAM_DELIVERY_QUEUE=true
ENABLE_ALERT_DELIVERY=true
MIN_REWARD_CONFIRMATIONS=10ADMIN_ID remains a backward-compatible fallback. New deployments should use explicit ADMIN_USER_ID and ADMIN_CHAT_ID; admin commands require the configured private admin chat.
See .env.example for health/readiness, timeouts, market history, webhook, retention, and monitoring settings.
Production runtime must use a least-privilege application role such as kaspa_pulse_app. Do not run the application as the PostgreSQL postgres superuser.
Schema changes belong in migrations/. Runtime schema creation is disabled by default:
ALLOW_RUNTIME_SCHEMA_ENSURE=falseUse an administrative database role only for migrations or privileged maintenance.
cargo fmt --all -- --check
cargo check --locked --all-targets --all-features
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo test --locked --all-targets --all-features
cargo run --locked --releaseBuild the production image:
docker build --pull -t kaspa-pulse:latest .Start with Compose:
docker compose up -d --buildThe production image:
- uses a Rust 1.97.1 / Debian 13 Trixie builder;
- uses a Debian 13 Trixie slim runtime;
- runs as non-root UID/GID
10001; - keeps the panic-recovery marker under
/var/lib/kaspa-pulse; - includes only the compiled binary and required runtime CA certificates.
Compose additionally enables an init process, drops Linux capabilities, sets no-new-privileges, limits JSON log rotation, and binds the published webhook port to host loopback by default.
When enabled, the service exposes local endpoints such as:
/healthz
/readyz
/metrics
Example checks:
curl http://127.0.0.1:18080/healthz
curl http://127.0.0.1:18080/readyz
curl http://127.0.0.1:18080/metricsDo not expose operational endpoints or the bot service directly to the public internet when a reverse proxy is expected.
Pull requests that change the Rust application run the core quality gate:
cargo fmt --all -- --check
cargo check --locked --all-targets --all-features
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo test --locked --all-targets --all-featuresProduction release, Docker build, and container smoke tests run on main/dev pushes and explicit manual runs. This keeps pull-request feedback focused while avoiding redundant hosted-runner work, even though this repository is public and standard GitHub-hosted Actions are not constrained by the private-repository minutes allowance.
Dependency/security automation includes:
cargo audit
cargo deny check
cargo machete
cargo tree --locked -dAdditional controls:
- GitHub Actions are pinned to immutable commit SHAs.
- Normal CI checkout does not persist repository credentials.
- Git dependencies are allow-listed in
deny.toml. rusty-kaspais pinned to an explicit release tag rather than a floating branch.- Dependabot checks Cargo, GitHub Actions, Docker, Rust toolchain, and Compose dependencies on staggered weekly schedules.
- The scheduled
rusty-kaspaupdater validates changes before publishing an update branch/PR. - Accepted upstream/transitive RustSec exceptions are documented in
SECURITY_ADVISORIES.md; they are not silently hidden. - Releases include a CycloneDX SBOM, SHA-256 checksum, Sigstore bundles, and SLSA/in-toto provenance.
- SUPPLY_CHAIN.md documents fail-closed verification of release provenance.
- security-insights.yml publishes the repository's OpenSSF Security Insights posture in a machine-readable format.
Read SECURITY.md before reporting a vulnerability. Submit unpatched vulnerabilities privately through GitHub's repository Security Advisories / Report a vulnerability flow rather than a public issue.
See SECURITY_ADVISORIES.md for documented upstream/transitive exceptions and their review policy, and SUPPLY_CHAIN.md for signed-release verification.
The repository ignores local secrets, database dumps, backups, logs, panic marker files, generated exports, and Rust build output.
If a real secret was ever committed, removing the latest file is not enough: rotate the credential immediately and rewrite Git history when the exposure requires it.
kaspa:qz0yqq8z3twwgg7lq2mjzg6w4edqys45w2wslz7tym2tc6s84580vvx9zr44g
Kaspa Pulse is licensed under the MIT License.