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 authority
  • name: Unique identifier for the schedule
  • period: Number of blocks between executions
  • msgs: Array of contract messages to execute
    • contract: Address of the contract to call
    • msg: JSON string of the message to send
  • execution_stage: When to execute (EXECUTION_STAGE_BEGIN_BLOCKER or EXECUTION_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:
  1. Proposal Period: Community can review the proposal
  2. Voting Period: NTRN token holders vote on the proposal
  3. 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

  1. Clear Documentation: Include detailed rationale for the schedule
  2. Community Engagement: Discuss the proposal with the community first
  3. Testing: Test your contract’s scheduled execution on testnet
  4. Monitoring: Plan for monitoring and maintenance of the schedule

Contract Design

  1. Idempotent Operations: Design scheduled tasks to be safely re-runnable
  2. Error Handling: Implement robust error handling for scheduled executions
  3. State Validation: Add checks to prevent unexpected state changes
  4. Logging: Include comprehensive logging with meaningful attributes
  5. Sender Verification: Optionally verify the sender is the Cron module account

Schedule Parameters

  1. Appropriate Periods: Choose block intervals that match your use case
    • Daily: ~7200 blocks (assuming 12-second blocks)
    • Weekly: ~50400 blocks
    • Monthly: ~216000 blocks
  2. Execution Stage: Choose BEGIN_BLOCKER or END_BLOCKER based on dependencies
  3. Message Format: Ensure messages are valid JSON strings for contract execution
  4. Atomicity: Group related operations in a single schedule for atomic execution
  5. 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

IssuePossible CauseSolution
Proposal rejectedInsufficient community supportEngage with community, revise proposal
Schedule not executingExecution failures or limit reachedCheck contract logic, monitor events
Execution failuresInvalid message format or contract errorsTest messages manually, check contract state
Schedule not foundGovernance proposal failedVerify proposal passed and was executed

Debugging Steps

  1. Verify Governance: Check if the governance proposal passed and was executed
  2. Query Schedule: Confirm the schedule exists with correct parameters
  3. Monitor Logs: Check validator logs for schedule execution information
  4. Test Manually: Execute the scheduled message manually to verify contract logic
  5. 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

  1. Proposal Review: Thoroughly review all governance proposals
  2. Community Oversight: Ensure adequate community review period
  3. Emergency Procedures: Understand Security SubDAO removal capabilities
  4. Testing: Always test on testnet before mainnet proposals

Contract Security

  1. Access Control: Consider implementing additional access controls in your contracts
  2. Input Validation: Validate all inputs in scheduled message handlers
  3. State Protection: Protect critical state from unauthorized modifications
  4. 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.