Overview
ProposalBot is a timer-based bot that continuously monitors the NNS (Network Nervous System) governance canister for new proposals and automatically broadcasts them to subscribed OpenChat groups and channels. It uses topic-based filtering to ensure subscribers only receive proposals relevant to their interests.Key Features
- Automated monitoring: Timer-based polling of NNS governance proposals
- Topic filtering: Subscribe to specific proposal topics (RVM, SCM, etc.)
- Batch processing: Groups related proposals (e.g., SCM with same git hash)
- Smart threading: Creates proposal threads with links to NNS Proposal Group
- Message matching: Links proposals to existing messages in NNS Group
How It Works
ProposalBot runs on a configurable timer (default 5 minutes) that:- Fetches new proposals from the NNS governance canister since the last check
- Matches proposals with existing messages in the NNS Proposal Group
- Groups proposals by type and git hash for batch updates
- Sends notifications to subscribed channels/groups based on topic filters
- Creates threads with links back to the original proposal messages
ProposalBot requires the timer to be initialized with
initTimer before it starts monitoring proposals.Architecture
Subscriber Type
Subscribers define where and what proposal updates to receive:Proposal Topics
Common NNS proposal topics:- 13 - RVM (Replica Version Management)
- 8 - SCM (Subnet Canister Management)
- Other topics as defined by NNS governance
Internal State
Getting Started
API Reference
initTimer
Starts the recurring timer that monitors for new proposals.Timer interval in seconds. Default: 300 (5 minutes)
Result<(), Text>
cancelTimer
Stops the automatic proposal monitoring. Authorization: Custodians only Returns:Result<(), Text>
update
Manually triggers a proposal update cycle (useful for testing).Optional proposal ID to start from. If null, continues from last processed proposal.
async ()
addSubscriber
Adds a new subscriber for proposal updates.Subscriber configuration with topics and destination
Optional invite code if joining private group/channel
Result<(), Text>
updateSubscriber
Updates the topic filter for an existing subscriber.Subscriber ID (group canister ID or channel ID as text)
New array of topic IDs to subscribe to
Result<(), Text>
deleteSubscriber
Removes a subscriber from receiving updates.Subscriber ID to remove
Result<(), Text>
getSubscribers
Retrieves all active subscribers. Returns:[Subscriber]
Update Mechanism
Proposal Lifecycle
- Discovery: Timer triggers
update()which fetches new proposals from NNS - Mapping: Proposals are added to
proposalsLookupmap - Matching: Bot matches proposals with messages in NNS Proposal Group
- Batching: Related proposals are grouped (SCM proposals with same git hash)
- Broadcasting: Messages sent to subscribers based on topic filters
- Cleanup: Processed proposals removed from lookup map
Batch Logic for SCM Proposals
SCM (Subnet Canister Management) proposals are intelligently batched:Batch Strategy
Separate proposals: Non-batched, separate build process detectedBatch proposals: Same git hash, sent in groups of up to 10Wait for quiet: Waits 3 timer cycles (15 min default) for more proposals
Message Matching
ProposalBot efficiently matches proposals with existing messages:- Scans NNS Proposal Group in batches of 100 messages
- Extracts proposal IDs from message content
- Updates
proposalsLookupwith message indexes - Stops when all proposals matched or reaches last processed index
Message Formatting
Single Proposal Thread
Batch Proposal Thread
Testing and Debugging
Manual Update
Trigger an update cycle manually:Check State
Reset State
Clear internal state for testing:Configuration
Constants
Topic Filtering
Proposals are filtered using topic IDs:Best Practices
Timer Configuration
- Default (5 min): Good balance for most use cases
- Shorter intervals: Use for time-sensitive communities
- Longer intervals: Reduce costs for less active communities
- Remember: Shorter intervals = higher cycle costs
Topic Selection
- Only subscribe to relevant topics to reduce noise
- RVM (13) and SCM (8) are the most common
- Test with a single topic before adding more
- Consider creating separate channels for different topics
Performance
- Bot uses efficient batch lookups (100 messages at a time)
- SCM proposals batched to reduce message spam
- Maintains state to avoid reprocessing proposals
- Uses “wait for quiet” logic for optimal batching
Troubleshooting
Timer not starting
Timer not starting
Common issues:
No proposals appearing
No proposals appearing
Debugging steps:
- Check last processed proposal:
- Manually trigger update:
- Check subscriber list:
- Verify topics in subscriber match proposal topics
addSubscriber returns error
addSubscriber returns error
“Subscriber already exists”: Delete first, then re-addJoin errors: Ensure bot has access to the group/channel and invite code is correct
Proposals not batching correctly
Proposals not batching correctly
SCM batching requires:
- Proposals must have the same git hash in description
- Either 10+ proposals accumulated OR 3 timer ticks elapsed
- Check logs for batching activity
High cycle consumption
High cycle consumption
Optimize cycle usage:
- Increase timer interval:
initTimer(opt 600)for 10 minutes - Reduce number of subscribers
- Limit topics per subscriber
- Check for stuck proposals in lookup map
Advanced Features
Post-Upgrade Timer Restoration
The timer automatically restarts after canister upgrades:Reentrancy Protection
Update cycles are protected from concurrent execution:Related Resources
TallyBot
Track neuron votes on proposals
Bot Service
Core bot functionality and OpenChat integration
Governance Service
NNS governance canister integration
Getting Started
Set up your first OpenChat bot