Skip to content
hopper
Get started
Safety / proc-macros

Proc macro policy

The public macro contract for account, context, program, instruction, and policy generation.

This reference covers Hopper 0.5.0, published on crates.io. See the release status for package verification, dated benchmarks, and remaining audit work.

Core Rule

No proc macros are required for correctness or core functionality.

Hopper must remain fully usable for layouts, overlays, pod access, validation, phases, receipts, compatibility checks, and migration tooling without relying on proc macros for soundness.

What proc macros may do

Proc macros are allowed for optional ergonomic and schema-generation tasks:

  • #[hopper::state] -- emit layout contracts and segment metadata
  • #[derive(Accounts)] -- emit first-touch typed account binding over Hopper runtime wrappers
  • #[hopper::context] -- emit lower-level typed account accessors for migrations and systems-mode code
  • #[hopper::program] -- emit dispatch glue over ordinary Hopper handlers
  • #[hopper::event] -- emit event types and metadata
  • #[hopper::args] -- emit borrowed instruction-argument parsers; the unreleased source also decodes &MyArgs handler parameters with recursive validation
  • #[derive(HopperInitSpace)] -- derive initialization space for Pod structs
  • hopper::canonical_pda! -- emit a canonical PDA and bump for explicit literal inputs

These generate validation, dispatch, and metadata code using Hopper runtime primitives. Equivalent code can be written manually. Removing an attribute without replacing its generated checks does not preserve program behavior.

For first-touch typed account contexts, this means proc macros may emit the Ctx<T> binding and ctx.accounts.* wrapper construction used by Account<'info, T>, Signer<'info>, Program<'info, P>, and related account types. For systems-mode context macros, generated helpers such as segment accessors and raw-account escape hatches must remain direct, inspectable calls into AccountView and Context, not hidden logic.

What proc macros must not do

Proc macros must not hide:

  • Memory model guarantees (alignment, bounds, aliasing)
  • Unsafe access patterns
  • Validation correctness
  • Compatibility rules
  • Phase transition semantics
  • Trust-critical runtime behavior

If a proc macro would make a user unable to understand the real runtime behavior by reading the code, it should not be part of Hopper's critical path.

Why this policy exists

Trust preservation

Users can always drop to explicit code and inspect what Hopper does. Every hopper_layout! expansion is a #[repr(C)] struct with known offsets and compile-time assertions. No hidden transforms.

Escape hatch preservation

Serious builders can use Hopper without buying into framework magic. The macro-free path (manual #[repr(C)] struct + Pod impl + FixedLayout impl) is always available and produces identical runtime behavior.

Product quality

Hopper can use proc macros to improve:

  • DX (less boilerplate for common patterns)
  • Schema generation (manifest/IDL export)
  • Documentation generation
  • Client tooling

without compromising its trust model.

Current macro inventory

Hopper provides optional proc macros through hopper-derive and declarative macros through its runtime surfaces. See the proc-macro inventory for the implemented attributes and derives. The following table lists declarative helpers:

Macro Purpose
hopper_layout! Define #[repr(C)] layout with fingerprint
hopper_dispatch! Instruction dispatch table
hopper_error! Sequential error code definitions
hopper_init! Account initialization
hopper_close! Account closure with sentinel
hopper_check! Inline validation assertion
hopper_require! Conditional error return
hopper_register_discs! Compile-time discriminator uniqueness
hopper_verify_pda! PDA seed verification
hopper_invariant! Invariant assertion
hopper_manifest! Manifest constant generation
hopper_segment! Segment descriptor
hopper_validate! Validation bundle
hopper_virtual! Virtual state slots
hopper_assert_compatible! Compile-time compat check
hopper_assert_fingerprint! Compile-time fingerprint check
hopper_interface! Cross-program read-only view

No proc macros required. This is a design choice, not a limitation.

Doctrine

Hopper does not require proc macros for correctness or core functionality. Proc macros are optional ergonomic and schema-generation tools only. The runtime model, memory model, validation model, and compatibility guarantees remain explicit and usable without them.