Layer LogoWAVS Docs
WAVS builders handbook

Triggers

A trigger prompts a WAVS service to run. Operators listen for the trigger event specified by the service and execute the corresponding component off-chain. Triggers can be any onchain event emitted from any contract.

Trigger lifecycle

  1. A service is deployed with a service.json manifest which contains information on the service and workflow logic (components, triggers, submission logic).

  2. Operators maintain lookup maps to track and verify triggers. For EVM and Cosmos events, they map chain names, contract addresses, and event identifiers to trigger IDs. Block interval triggers are tracked by chain name with countdown timers, while cron triggers are managed in a priority queue ordered by execution time.

  3. When a trigger is detected, operators verify it against their lookup maps according to trigger type. If a match is found, a TriggerAction is created with the trigger configuration and event data.

  4. TriggerAction has 2 fields: TriggerConfig which contains the service, workflow, and trigger configuration, and TriggerDatacontains the trigger data based on the trigger type.

pub struct TriggerAction {
pub config: TriggerConfig, // Contains service_id, workflow_id, and trigger type
pub data: TriggerData, // Contains the actual trigger data
}
pub struct TriggerConfig {
pub service_id: ServiceID,
pub workflow_id: WorkflowID,
pub trigger: Trigger,
}
pub enum TriggerData {
CosmosContractEvent { //For Cosmos event triggers
contract_address: layer_climb_address::Address, /// The address of the contract that emitted the event
chain_name: ChainName, /// The name of the chain where the event was emitted
event: cosmwasm_std::Event, /// The data that was emitted by the contract
block_height: u64, /// The block height where the event was emitted
},
EvmContractEvent { //For EVM event triggers
contract_address: alloy_primitives::Address, /// The address of the contract that emitted the event
chain_name: ChainName, /// The name of the chain where the event was emitted
log: LogData, /// The raw event log
block_height: u64, /// The block height where the event was emitted
},
BlockInterval { //For block interval triggers
chain_name: ChainName, /// The name of the chain where the blocks are checked
block_height: u64, /// The block height where the event was emitted
},
Cron { //For cron triggers
trigger_time: Timestamp, /// The trigger time
}
}
  1. The TriggerAction is converted to a WASI-compatible format and passed to the component where it is decoded and processed. The component decodes the incoming event trigger data using the decode_event_log_data! macro from the wavs-wasi-utils crate. Visit the components page for more information on decoding and processing trigger data in your component.

Trigger configuration

Triggers define when and how the component should be executed. Each workflow needs a trigger to be set. They are set in the trigger field of the service.json file.

EVM event trigger

This trigger listens for specific events emitted by contracts on EVM-compatible chains, executing the component when a matching event is detected. Event triggers pass raw log data to the component.

"trigger": {
"evm_contract_event": {
"address": "0x00000000219ab540356cbb839cbe05303d7705fa", // Contract address to monitor
"chain_name": "ethereum", // Chain to monitor
"event_hash": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef" // Event hash (32 bytes)
}
}

Your evm chain information must be set in wavs.toml under the [default.chains.evm.<chain_name>] section:

wavs.toml
# Mainnet
[default.chains.evm.ethereum]
chain_id = "1"
ws_endpoint = "wss://eth.drpc.org"
http_endpoint = "https://eth.drpc.org"

You'll need to set your EVM chain credential in your .env file to establish a connection for monitoring the EVM chain:

.env
WAVS_CLI_EVM_CREDENTIAL="0x5ze146f435835b1762ed602088740d201b68fd94bf808f97fd04588f1a63c9ab"

Cosmos event trigger

This trigger monitors events emitted by Cosmos smart contracts, executing your component when a matching event type is detected from the specified contract address. Cosmos event triggers pass the contract data that was emitted by the contract to the component.

"trigger": {
"cosmos_contract_event": {
"address": {
"Cosmos": {
"bech32_addr": "neutron1qlaq54uh9f52d3p66q77s6kh9k9ee3vasy8gkdkk3yvgezcs6zts0mkcv4", // Contract address to monitor
"prefix_len": 7 // Length of the Bech32 prefix (7 for Neutron)
}
},
"chain_name": "neutron", // Chain to monitor
"event_type": "send_nft" // Event type to watch
}
},

Your chain information must be set in wavs.toml under the [default.chains.cosmos.<chain_name>] section:

wavs.toml
# == Cosmos chains ==
[default.chains.cosmos.neutron]
chain_id = "pion-1"
bech32_prefix = "neutron"
rpc_endpoint = "https://rpc-falcron.pion-1.ntrn.tech"
grpc_endpoint = "http://grpc-falcron.pion-1.ntrn.tech:80"
gas_price = 0.0053
gas_denom = "untrn"

Your Cosmos mnemonic must be set in your .env file to establish a connection for monitoring the Cosmos chain:

.env
WAVS_CLI_COSMOS_MNEMONIC="large slab plate twenty laundry illegal vacuum phone drum example topic reason"

Cron trigger

Executes your component on a schedule defined by a cron expression, with optional start and end times to control the execution window. If no start or end time is provided, the component will start immediately and run indefinitely. Cron triggers pass the trigger timestamp to the component.

"trigger": {
"cron": {
"schedule": "0 */5 * * * *", // Every 5 minutes (at 0 seconds)
"start_time": 1704067200000000000, // Optional start time in nanoseconds since Unix epoch (2024-01-01T00:00:00Z) (default: null)
"end_time": 1735689599000000000 // Optional end time in nanoseconds since Unix epoch (default: null)
}
}
// Cron Expression Format:
// * * * * * *
// │ │ │ │ │ │
// │ │ │ │ │ └── Day of week (0-6, where 0 is Sunday)
// │ │ │ │ └──── Month (1-12)
// │ │ │ └────── Day of month (1-31)
// │ │ └──────── Hour (0-23)
// │ └────────── Minute (0-59)
// └──────────── Second (0-59)
//
// Each field can be:
// - A number: `5` (exact time)
// - A range: `1-5` (1 through 5)
// - A list: `1,3,5` (1, 3, and 5)
// - A step: `*/5` (every 5 units)
// - An asterisk: `*` (every unit)
//
// Common examples:
// - `0 */5 * * * *` - Every 5 minutes (at 0 seconds)
// - `0 0 */6 * * *` - Every 6 hours (at 0 minutes and 0 seconds)
// - `0 0 0 * * *` - Every day at midnight (00:00:00)
// - `0 0 12 * * *` - Every day at noon (12:00:00)
// - `0 0 12 1 * *` - Noon on the first day of every month
// - `0 0 12 * * 1` - Noon every Monday

Crontab.guru is a helpful tool for making cron expressions.

Cron trigger latency

There may be slight variations in Cron trigger execution time between operators due to network latency and clock drift. Cron triggers are best suited for tasks that don't require precise synchronization between operators:

  • Triggering components that don't need exact synchronization.
  • Collecting data from external services with monotonic pagination.
  • Background tasks where eventual consistency is acceptable.

If you need precise timing synchronization between operators, consider using block-based triggers instead.

Block trigger

Executes your component at regular block intervals on a specified EVM or Cosmos chain, useful for chain-specific operations that need to run periodically. Block interval triggers pass the block height and chain name to the component.

"trigger": {
"block_interval": {
"chain_name": "ethereum-mainnet",
"n_blocks": 10,
"start_block": null, // Optional blockheight to start
"end_block": null // Optional blockheight to end
}
}

Edit on GitHub

On this page