Skip to content

Commit ef1908a

Browse files
committed
docs: complete README, examples, and release setup
- Rewrite README with natural, human tone and complete quickstart - Add examples/evm_usdc_whale with USDC monitoring config - Add examples/algo_app_watch with Algorand app monitoring - Add GitHub release workflow for automated releases - Enhance goreleaser config with release notes template - Add RELEASE_NOTES.md for v0.1.0 - Update Dockerfile to use Go 1.23
1 parent b279b8a commit ef1908a

12 files changed

Lines changed: 401 additions & 3 deletions

File tree

.github/workflows/release.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Set up Go
21+
uses: actions/setup-go@v5
22+
with:
23+
go-version: '1.23'
24+
25+
- name: Run GoReleaser
26+
uses: goreleaser/goreleaser-action@v5
27+
with:
28+
distribution: goreleaser
29+
version: latest
30+
args: release --clean
31+
env:
32+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.goreleaser.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,22 @@ checksum:
2424
sboms:
2525
- artifacts: archive
2626

27+
release:
28+
mode: replace
29+
header: |
30+
## {{ .Tag }}
31+
32+
{{ .ReleaseNotes }}
33+
34+
footer: |
35+
## Installation
36+
37+
Download the binary for your platform from the assets below, or install via Go:
38+
39+
```bash
40+
go install github.com/devblac/watch-tower/cmd/watch-tower@{{ .Tag }}
41+
```
42+
43+
See the [README](https://github.com/devblac/watch-tower#quick-start) for usage instructions.
44+
45+

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.22-bookworm AS build
1+
FROM golang:1.23-bookworm AS build
22
WORKDIR /src
33
COPY . .
44
RUN go mod download

README.md

13.4 KB
Binary file not shown.

RELEASE_NOTES.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# Release Notes
2+
3+
## v0.1.0 (2025-12-22)
4+
5+
First stable release of watch-tower! 🎉
6+
7+
### What's New
8+
9+
**Core Features:**
10+
- Cross-chain monitoring for EVM chains (Ethereum, Polygon, etc.) and Algorand
11+
- Declarative YAML configuration with environment variable interpolation
12+
- Reorg-safe block processing with configurable confirmations
13+
- Exactly-once alert delivery via SQLite ledger
14+
- Built-in deduplication with TTL-based expiration
15+
16+
**Event Matching:**
17+
- EVM event log matching with ABI decoding
18+
- Algorand application call and asset transfer monitoring
19+
- Simple predicate expressions (`==`, `!=`, `>`, `<`, `in`, `contains`)
20+
- Numeric helpers for wei and microAlgos
21+
22+
**Alerting:**
23+
- Slack webhook integration
24+
- Microsoft Teams webhook support
25+
- Generic HTTP webhook with customizable templates
26+
- Template system with helpers (`pretty_json`, `short_addr`)
27+
28+
**Operational:**
29+
- Health check endpoint (`/healthz`) for DB and RPC status
30+
- Optional Prometheus metrics endpoint (`/metrics`)
31+
- Structured logging with secret redaction
32+
- Configurable log levels (debug, info, warn, error)
33+
34+
**CI-Friendly:**
35+
- `--dry-run` mode for testing without sending alerts
36+
- `--once` flag for single-pass execution
37+
- `--from/--to` flags for historical replay
38+
- `validate` command for config and RPC connectivity checks
39+
40+
**CLI Commands:**
41+
- `watch-tower init` - Scaffold configuration files
42+
- `watch-tower validate -c config.yaml` - Validate config and test RPCs
43+
- `watch-tower run -c config.yaml` - Run the monitoring pipeline
44+
- `watch-tower state` - Show current cursors and status
45+
- `watch-tower export` - Export alerts and cursors (JSON/CSV)
46+
- `watch-tower version` - Show version information
47+
48+
### Examples
49+
50+
Two complete examples are included:
51+
- `examples/evm_usdc_whale/` - Monitor large USDC transfers on Ethereum
52+
- `examples/algo_app_watch/` - Monitor Algorand application calls
53+
54+
### Installation
55+
56+
**Download binaries:**
57+
- Linux (amd64/arm64): `watch-tower_*_linux_*.tar.gz`
58+
- macOS (amd64/arm64): `watch-tower_*_darwin_*.tar.gz`
59+
- Windows (amd64/arm64): `watch-tower_*_windows_*.zip`
60+
61+
**Or install via Go:**
62+
```bash
63+
go install github.com/devblac/watch-tower/cmd/watch-tower@v0.1.0
64+
```
65+
66+
**Docker:**
67+
```bash
68+
docker pull ghcr.io/devblac/watch-tower:v0.1.0
69+
```
70+
71+
### Documentation
72+
73+
- [README](https://github.com/devblac/watch-tower#readme) - Quick start and configuration guide
74+
- [Examples](https://github.com/devblac/watch-tower/tree/main/examples) - Working example configurations
75+
- [Contributing](https://github.com/devblac/watch-tower/blob/main/CONTRIBUTING.md) - Development guidelines
76+
77+
### Breaking Changes
78+
79+
None - this is the first release!
80+
81+
### Known Limitations
82+
83+
- Predicates are simple expressions only (no complex joins or time windows)
84+
- SQLite storage only (Postgres option coming later)
85+
- Basic sink types (Slack, Teams, Webhook)
86+
- No hot reload of configuration (restart required)
87+
88+
### What's Next
89+
90+
See the [roadmap](https://github.com/devblac/watch-tower/blob/main/tasks.md) for planned features:
91+
- More chains (Solana, Base, Arbitrum, Optimism)
92+
- Additional sinks (PagerDuty, Opsgenie, Email)
93+
- Enhanced predicate language
94+
- Postgres storage option
95+
- Hot reload support
96+
97+
### Thanks
98+
99+
Thanks to all contributors and early testers! This release represents months of development focused on reliability and simplicity.
100+
101+
### Security
102+
103+
If you find a security vulnerability, please report it privately via [SECURITY.md](https://github.com/devblac/watch-tower/blob/main/SECURITY.md).
104+
105+
---
106+
107+
**Full Changelog**: https://github.com/devblac/watch-tower/compare/v0.0.0...v0.1.0

examples/algo_app_watch/README.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Algorand Application Call Monitor
2+
3+
This example monitors calls to a specific Algorand application and alerts when certain conditions are met.
4+
5+
## Setup
6+
7+
1. **Get Algorand node URLs**:
8+
- Algod URL: Usually `https://mainnet-api.algonode.cloud` (public) or your own node
9+
- Indexer URL: Usually `https://mainnet-idx.algonode.cloud` (public) or your own indexer
10+
11+
2. **Get a Slack webhook** (optional): Create a Slack app and add an incoming webhook.
12+
13+
3. **Set environment variables**:
14+
15+
```bash
16+
export ALGOD_URL="https://mainnet-api.algonode.cloud"
17+
export ALGO_INDEXER_URL="https://mainnet-idx.algonode.cloud"
18+
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
19+
export ALLOWED_SENDERS="ADDRESS1,ADDRESS2" # optional: filter by sender
20+
```
21+
22+
4. **Update the app ID** in `config.yaml` to the application you want to monitor.
23+
24+
5. **Run**:
25+
26+
```bash
27+
watch-tower validate -c config.yaml
28+
watch-tower run -c config.yaml --once
29+
```
30+
31+
## What it does
32+
33+
- Monitors calls to a specific Algorand application
34+
- Filters by sender addresses (if `ALLOWED_SENDERS` is set)
35+
- Sends alerts to Slack
36+
- Deduplicates alerts for 24 hours
37+
38+
## Customization
39+
40+
**Monitor a different app:**
41+
```yaml
42+
match:
43+
type: app_call
44+
app_id: 12345678 # Change to your app ID
45+
```
46+
47+
**Monitor ASA transfers instead:**
48+
```yaml
49+
match:
50+
type: asset_transfer
51+
# No app_id needed for asset transfers
52+
```
53+
54+
**Add predicates:**
55+
```yaml
56+
where:
57+
- "sender in env(ALLOWED_SENDERS)"
58+
- "amount >= microAlgos(1000000)" # 1 ALGO
59+
```
60+
61+
## Testing
62+
63+
Test with dry-run:
64+
```bash
65+
watch-tower run -c config.yaml --dry-run --once
66+
```
67+
68+
## Finding app IDs
69+
70+
Use AlgoExplorer or the Algorand indexer API to find application IDs:
71+
```bash
72+
curl "https://mainnet-idx.algonode.cloud/v2/applications?creator=ADDRESS"
73+
```
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
version: 1
2+
global:
3+
db_path: "./watch_tower.db"
4+
confirmations:
5+
algorand: 10
6+
sources:
7+
- id: algorand_mainnet
8+
type: algorand
9+
algod_url: ${ALGOD_URL}
10+
indexer_url: ${ALGO_INDEXER_URL}
11+
start_round: "latest-10000"
12+
rules:
13+
- id: app_call_monitor
14+
source: algorand_mainnet
15+
match:
16+
type: app_call
17+
app_id: 12345678 # Change this to your app ID
18+
where:
19+
- "sender in env(ALLOWED_SENDERS)" # Optional: filter by sender
20+
sinks: ["slack"]
21+
dedupe:
22+
key: "txhash"
23+
ttl: "24h"
24+
sinks:
25+
- id: slack
26+
type: slack
27+
webhook_url: ${SLACK_WEBHOOK_URL}
28+
template: "📱 Algorand App Call\n\nApp ID: {{app_id}}\nSender: {{sender}}\nTx: {{txhash}}\nRound: {{height}}"

examples/algo_app_watch/run.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
# Quick run script for Algorand app monitoring
3+
4+
set -e
5+
6+
if [ ! -f .env ]; then
7+
echo "Error: .env file not found"
8+
echo "Copy .env.example to .env and fill in your values"
9+
exit 1
10+
fi
11+
12+
source .env
13+
14+
if [ -z "$ALGOD_URL" ] || [ -z "$ALGO_INDEXER_URL" ] || [ -z "$SLACK_WEBHOOK_URL" ]; then
15+
echo "Error: ALGOD_URL, ALGO_INDEXER_URL, and SLACK_WEBHOOK_URL must be set in .env"
16+
exit 1
17+
fi
18+
19+
echo "Validating config..."
20+
watch-tower validate -c config.yaml
21+
22+
echo "Running watch-tower (press Ctrl+C to stop)..."
23+
watch-tower run -c config.yaml

examples/evm_usdc_whale/README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# EVM USDC Whale Alert
2+
3+
This example monitors USDC transfers on Ethereum mainnet and alerts when transfers exceed 1 million USDC.
4+
5+
## Setup
6+
7+
1. **Get an RPC endpoint**: Sign up for a free RPC provider (Alchemy, Infura, QuickNode) and get your endpoint URL.
8+
9+
2. **Get a Slack webhook** (optional): Create a Slack app and add an incoming webhook to your channel.
10+
11+
3. **Set environment variables**:
12+
13+
```bash
14+
export EVM_RPC_URL="https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"
15+
export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
16+
```
17+
18+
4. **Run**:
19+
20+
```bash
21+
watch-tower validate -c config.yaml
22+
watch-tower run -c config.yaml --once
23+
```
24+
25+
## What it does
26+
27+
- Monitors USDC contract (`0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48`) on Ethereum
28+
- Triggers on transfers >= 1,000,000 USDC (1M * 1e6, since USDC has 6 decimals)
29+
- Sends alerts to Slack
30+
- Deduplicates alerts for 24 hours using transaction hash + log index
31+
32+
## Customization
33+
34+
**Change the threshold:**
35+
```yaml
36+
where:
37+
- "value >= 5_000_000 * 1e6" # 5M USDC instead
38+
```
39+
40+
**Add more conditions:**
41+
```yaml
42+
where:
43+
- "value >= 1_000_000 * 1e6"
44+
- "to != 0x0000000000000000000000000000000000000000" # exclude burns
45+
```
46+
47+
**Use a different chain:**
48+
Change the `rpc_url` to point to Polygon, Arbitrum, or any EVM chain.
49+
50+
**Add rate limiting:**
51+
```yaml
52+
rate_limit:
53+
capacity: 5
54+
rate: 0.5 # max 5 alerts, refill at 0.5/sec
55+
```
56+
57+
## Testing
58+
59+
Test with dry-run first:
60+
```bash
61+
watch-tower run -c config.yaml --dry-run --once
62+
```
63+
64+
This processes events but doesn't send alerts, perfect for validating your setup.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
version: 1
2+
global:
3+
db_path: "./watch_tower.db"
4+
confirmations:
5+
evm: 12
6+
sources:
7+
- id: ethereum_mainnet
8+
type: evm
9+
rpc_url: ${EVM_RPC_URL}
10+
start_block: "latest-5000"
11+
abi_dirs: ["./abis"]
12+
rules:
13+
- id: usdc_whale
14+
source: ethereum_mainnet
15+
match:
16+
type: log
17+
contract: "0xA0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
18+
event: "Transfer(address,address,uint256)"
19+
where:
20+
- "value >= 1_000_000 * 1e6"
21+
sinks: ["slack"]
22+
dedupe:
23+
key: "txhash:logIndex"
24+
ttl: "24h"
25+
sinks:
26+
- id: slack
27+
type: slack
28+
webhook_url: ${SLACK_WEBHOOK_URL}
29+
template: "🐋 Large USDC Transfer\n\nAmount: {{value}} USDC\nFrom: {{from}}\nTo: {{to}}\nTx: {{txhash}}\nBlock: {{height}}"

0 commit comments

Comments
 (0)