Skip to main content
Triggers select when assertion functions execute. Match the trigger to the state or operation that the policy checks.

Why Use Triggers?

Scoped triggers reduce execution cost. Choose a trigger that covers every path that can violate the policy.

Trigger Behavior in Production

Each matching assertion executes independently. A participating builder excludes a candidate if any active production assertion fails.

Trigger Types

Function Call Triggers

Use registerFnCallTrigger when an assertion should run once for each successful call to a specific function. This is the preferred trigger for call-scoped checks because the assertion can read ph.context() and construct PhEvm.ForkId({forkType: 2, callIndex: ctx.callStart}) / PhEvm.ForkId({forkType: 3, callIndex: ctx.callEnd}) snapshots for the matched call. Example:

Transaction End Triggers

Use registerTxEndTrigger when an assertion should run after any transaction that touches the protected contract. This is the preferred trigger for transaction-wide invariants where the relevant mutation can happen through multiple functions or indirect calls. Example:

State and Flow Triggers

Choose a narrower trigger when it still covers every mutation that matters: Storage triggers remain supported in current patterns. Use registerFnCallTrigger instead of legacy registerCallTrigger for new call-scoped policies. See the library reference for helper signatures and specification requirements.

Best Practices

Test that the trigger covers all relevant state changes, including indirect calls and alternative entry points. Narrow it only when those tests still pass.

Assertions Overview

Learn about assertions and how they work

Cheatcodes Reference

Complete API reference for trigger registration

Use Cases Book

Real-world assertion examples and implementations

Testing Assertions

How to test your assertions and triggers