How-to
This guide provides practical instructions for working with the Cron module, including creating governance proposals for schedules and handling scheduled executions in smart contracts.
Prerequisites
- Understanding of Neutron governance processes
- Familiarity with CosmWasm contract development
- Access to governance proposal submission (for schedule creation)
Understanding Cron Module Access
The Cron module is governance-gated, meaning:
- Only governance can create or remove schedules
- Individual users and contracts cannot directly interact with this module
- Schedule management requires proposals to either:
- Main DAO: Can create and remove any schedule
- Security SubDAO: Can remove schedules (emergency situations)
No Individual Access: Unlike other modules, the Cron module does not accept direct user transactions. All schedule management must go through governance proposals.
Neutron uses a modular governance system with specialized subDAOs that handle different aspects of network management. The Security SubDAO can remove schedules in emergency situations, providing a safety mechanism for the network.
Creating Schedules Through Governance
Step 1: Prepare Your Governance Proposal
To create a schedule, you need to submit a governance proposal using the DAO contract format. Here's the structure for adding a schedule:
{
"title": "Add Daily Reward Distribution Schedule",
"description": "Creates a schedule to distribute rewards every 7200 blocks (approximately daily)",
"messages": [
{
"@type": "/neutron.cron.MsgAddSchedule",
"authority": "neutron1...",
"name": "daily_rewards",
"period": 7200,
"msgs": [
{
"contract": "neutron1contract...",
"msg": "{\"distribute_rewards\": {\"amount\": \"1000\"}}"
}
],
"execution_stage": "EXECUTION_STAGE_END_BLOCKER"
}
]
}
Step 2: Understanding the Message Structure
The MsgAddSchedule message contains:
authority: Address of the governance authorityname: Unique identifier for the scheduleperiod: Number of blocks between executionsmsgs: Array of contract messages to executecontract: Address of the contract to callmsg: JSON string of the message to send
execution_stage: When to execute (EXECUTION_STAGE_BEGIN_BLOCKERorEXECUTION_STAGE_END_BLOCKER)
Step 3: Submit the Governance Proposal
Standard Governance Proposal
Submit the proposal using the standard governance module:
# Submit governance proposal
neutrond tx gov submit-proposal [proposal-file.json] \
--from=<your-key> \
--chain-id=neutron-1 \
--gas=auto \
--gas-adjustment=1.5
Step 4: Governance Voting Process
Once submitted, the proposal goes through the standard governance process:
- Proposal Period: Community can review the proposal
- Voting Period: NTRN token holders vote on the proposal
- Execution: If passed, the schedule is automatically created
Preparing Your Contract for Scheduled Execution
Handle Scheduled Messages
Your contract must be prepared to receive messages from the Cron module account:
use cosmwasm_std::{
entry_point, DepsMut, Env, MessageInfo, Response, StdResult,
};
#[entry_point]
pub fn execute(
deps: DepsMut,
env: Env,
info: MessageInfo,
msg: ExecuteMsg,
) -> StdResult<Response> {
match msg {
ExecuteMsg::DistributeRewards { amount } => {
handle_scheduled_execution(deps, env, info, amount)
},
// Other handlers...
}
}
fn handle_scheduled_execution(
deps: DepsMut,
env: Env,
info: MessageInfo,
amount: String,
) -> StdResult<Response> {
// Note: The sender will be the Cron module account
// You can optionally validate this if needed
// Perform your scheduled task
// This could be:
// - Updating state
// - Distributing rewards
// - Triggering other contract calls
// - Protocol maintenance tasks
Ok(Response::new()
.add_attribute("action", "scheduled_task_executed")
.add_attribute("sender", info.sender.to_string())
.add_attribute("block_height", env.block.height.to_string())
.add_attribute("amount", amount))
}
Design Considerations
When designing your contract for scheduled execution:
// Example: Periodic reward distribution with safety checks
fn handle_scheduled_execution(
deps: DepsMut,
env: Env,
info: MessageInfo,
amount: String,
) -> StdResult<Response> {
// Optional: Verify sender is Cron module (for extra security)
let cron_module_addr = "neutron1..."; // Known Cron module address
if info.sender != cron_module_addr {
return Err(StdError::generic_err("Unauthorized: not from Cron module"));
}
// Check if execution is appropriate (additional safety check)
let last_execution = LAST_EXECUTION.may_load(deps.storage)?.unwrap_or(0);
let blocks_since_last = env.block.height - last_execution;
if blocks_since_last < MIN_BLOCKS_BETWEEN_EXECUTIONS {
return Ok(Response::new()
.add_attribute("action", "execution_skipped")
.add_attribute("reason", "too_early"));
}
// Perform the actual task
distribute_rewards(deps, env, amount)?;
// Update last execution height
LAST_EXECUTION.save(deps.storage, &env.block.height)?;
Ok(Response::new()
.add_attribute("action", "rewards_distributed")
.add_attribute("height", env.block.height.to_string())
.add_attribute("amount", amount))
}
Common Use Cases and Examples
Protocol Maintenance
For regular protocol maintenance tasks:
{
"title": "Add Daily Protocol Maintenance Schedule",
"description": "Performs daily maintenance tasks every 7200 blocks",
"messages": [
{
"@type": "/neutron.cron.MsgAddSchedule",
"authority": "neutron1...",
"name": "daily_maintenance",
"period": 7200,
"msgs": [
{
"contract": "neutron1protocol_contract...",
"msg": "{\"perform_maintenance\": {}}"
}
],
"execution_stage": "EXECUTION_STAGE_END_BLOCKER"
}
]
}
Reward Distribution
For periodic reward distribution:
{
"title": "Add Weekly Reward Distribution Schedule",
"description": "Distributes rewards every 50400 blocks (approximately weekly)",
"messages": [
{
"@type": "/neutron.cron.MsgAddSchedule",
"authority": "neutron1...",
"name": "weekly_rewards",
"period": 50400,
"msgs": [
{
"contract": "neutron1rewards_contract...",
"msg": "{\"distribute_rewards\": {\"validator\": \"channel-52\", \"recipient\": \"neutron123...\"}}"
}
],
"execution_stage": "EXECUTION_STAGE_END_BLOCKER"
}
]
}
Multi-Message Schedule
For complex operations requiring multiple contract calls:
{
"title": "Add Multi-Step Protocol Update Schedule",
"description": "Performs multi-step protocol update every 100800 blocks",
"messages": [
{
"@type": "/neutron.cron.MsgAddSchedule",
"authority": "neutron1...",
"name": "protocol_update",
"period": 100800,
"msgs": [
{
"contract": "neutron1contract1...",
"msg": "{\"prepare_update\": {}}"
},
{
"contract": "neutron1contract2...",
"msg": "{\"apply_update\": {\"version\": \"2.0\"}}"
},
{
"contract": "neutron1contract3...",
"msg": "{\"notify_update_complete\": {}}"
}
],
"execution_stage": "EXECUTION_STAGE_END_BLOCKER"
}
]
}
Removing Schedules
Standard Removal (Main DAO)
To remove a schedule through Main DAO governance:
{
"title": "Remove Daily Reward Distribution Schedule",
"description": "Removes the daily rewards distribution schedule as it's no longer needed",
"messages": [
{
"@type": "/neutron.cron.MsgRemoveSchedule",
"authority": "neutron1...",
"name": "daily_rewards"
}
]
}
Emergency Removal (Security SubDAO)
The Security SubDAO can also submit remove_schedule proposals for emergency situations:
{
"title": "Emergency Removal of Malfunctioning Schedule",
"description": "Emergency removal of schedule causing network issues",
"messages": [
{
"@type": "/neutron.cron.MsgRemoveSchedule",
"authority": "neutron1...",
"name": "problematic_schedule"
}
]
}
Best Practices
Governance Proposal Strategy
- Clear Documentation: Include detailed rationale for the schedule
- Community Engagement: Discuss the proposal with the community first
- Testing: Test your contract's scheduled execution on testnet
- Monitoring: Plan for monitoring and maintenance of the schedule
Contract Design
- Idempotent Operations: Design scheduled tasks to be safely re-runnable
- Error Handling: Implement robust error handling for scheduled executions
- State Validation: Add checks to prevent unexpected state changes
- Logging: Include comprehensive logging with meaningful attributes
- Sender Verification: Optionally verify the sender is the Cron module account
Schedule Parameters
- Appropriate Periods: Choose block intervals that match your use case
- Daily: ~7200 blocks (assuming 12-second blocks)
- Weekly: ~50400 blocks
- Monthly: ~216000 blocks
- Execution Stage: Choose BEGIN_BLOCKER or END_BLOCKER based on dependencies
- Message Format: Ensure messages are valid JSON strings for contract execution
- Atomicity: Group related operations in a single schedule for atomic execution
- Descriptive Names: Use clear, descriptive names that indicate the schedule's purpose
Monitoring and Troubleshooting
Querying Schedules
To check existing schedules:
# List all schedules
neutrond query cron list-schedule
# Get specific schedule
neutrond query cron show-schedule <schedule-name>
# Check module parameters
neutrond query cron params
Common Issues and Solutions
| Issue | Possible Cause | Solution |
|---|---|---|
| Proposal rejected | Insufficient community support | Engage with community, revise proposal |
| Schedule not executing | Execution failures or limit reached | Check contract logic, monitor events |
| Execution failures | Invalid message format or contract errors | Test messages manually, check contract state |
| Schedule not found | Governance proposal failed | Verify proposal passed and was executed |
Debugging Steps
- Verify Governance: Check if the governance proposal passed and was executed
- Query Schedule: Confirm the schedule exists with correct parameters
- Monitor Logs: Check validator logs for schedule execution information
- Test Manually: Execute the scheduled message manually to verify contract logic
- Check Limits: Ensure the schedule isn't being skipped due to block limits
Event Monitoring
The Cron module does not emit blockchain events. Schedule execution and management operations are logged internally but do not generate events that can be monitored externally. Use the query commands to check schedule status and execution history.
Security Considerations
Governance Security
- Proposal Review: Thoroughly review all governance proposals
- Community Oversight: Ensure adequate community review period
- Emergency Procedures: Understand Security SubDAO removal capabilities
- Testing: Always test on testnet before mainnet proposals
Contract Security
- Access Control: Consider implementing additional access controls in your contracts
- Input Validation: Validate all inputs in scheduled message handlers
- State Protection: Protect critical state from unauthorized modifications
- Failure Handling: Handle execution failures gracefully without breaking contract state
This governance-gated approach ensures that only approved schedules run on the network, maintaining security and preventing spam while enabling powerful automation capabilities for the Neutron ecosystem.