Skip to content
hopper
Get started
Operations / schema

Schema architecture

Program manifests, layout IDs, Hopper IDL, Codama JSON, lossless Solana IDL projection, and compatibility diffs.

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

One canonical schema model

Hopper has one source of truth for state and program semantics: the Rust code. Layout macros, instruction declarations, event definitions, and policy bindings are the authoritative definitions. They assemble one ProgramManifest, from which Hopper renders the rich Hopper manifest plus nine client/interoperability outputs:

  1. Six clients: TypeScript, Kotlin, Python, Go, C, and off-chain Rust
  2. Hopper's public IDL subset
  3. Codama JSON
  4. A Solana IDL v0.1.0 projection, only when the wire contract is lossless

These outputs share a source, but they are not interchangeable formats.

Code-First Doctrine

Canonical truth lives in code. The authoritative declarations are:

  • hopper_layout! -- fields, offsets, sizes, versions, fingerprints
  • hopper_segment! / segmented layouts -- segment structure, roles
  • hopper_dispatch! -- instruction set, discriminators
  • hopper_error! -- error codes and variants
  • Policy constants -- capability-requirement bindings
  • hopper_interface! -- cross-program read-only views

These declarations produce compile-time constants (LAYOUT_ID, LEN, DISC, VERSION) that are deterministic and verifiable. The schema layer reads these constants to build manifests and IDLs without duplicating truth.

Proc Macro Policy

No proc macros are required for correctness or core functionality. Proc macros are allowed only for:

  • Schema derivation (#[derive(HopperSchema)])
  • Manifest export
  • IDL generation
  • Optional boilerplate reduction

See PROC_MACRO_POLICY.md for the full doctrine.

The Hopper Manifest

Purpose

The Manifest is Hopper's rich internal schema. It powers:

  • hopper explain / hopper inspect
  • hopper compat / hopper diff / hopper plan
  • hopper manager (program introspection)
  • Receipt rendering and migration planning
  • Docs generation and test tooling

File format

hopper.manifest.json

The version string in this structure is an illustrative 0.2.1 fixture value, not the current Hopper package version.

Structure

{
  "format": "hopper-manifest",
  "version": 1,
  "program": {
    "name": "hopper_registry",
    "program_id": "...",
    "version": "0.2.1",
    "description": "Segmented registry example"
  },
  "layouts": [
    {
      "name": "Vault",
      "kind": "fixed",
      "version": 1,
      "discriminator": 1,
      "layout_id": "a1b2c3d4e5f60718",
      "size": 57,
      "header_size": 16,
      "fields": [
        { "name": "authority", "type": "[u8;32]", "size": 32, "offset": 16 },
        { "name": "balance", "type": "WireU64", "size": 8, "offset": 48 },
        { "name": "bump", "type": "u8", "size": 1, "offset": 56 }
      ],
      "segments": [],
      "compatibility": {
        "append_safe": true,
        "compatible_from": [1],
        "migration_required_from": []
      }
    }
  ],
  "instructions": [
    {
      "name": "deposit",
      "tag": 1,
      "args": [
        { "name": "amount", "type": "u64", "size": 8 }
      ],
      "accounts": [
        { "name": "depositor", "writable": false, "signer": true },
        { "name": "vault", "writable": true, "signer": false, "layout_ref": "Vault" }
      ],
      "capabilities": ["MutatesState", "MutatesTreasury"],
      "policy_pack": "TREASURY_WRITE",
      "receipt_expected": true
    }
  ],
  "events": [
    {
      "name": "DepositEvent",
      "tag": 1,
      "fields": [
        { "name": "authority", "type": "[u8;32]", "size": 32 },
        { "name": "amount", "type": "u64", "size": 8 }
      ]
    }
  ],
  "policies": [
    {
      "name": "TREASURY_WRITE",
      "capabilities": ["MutatesState", "MutatesTreasury"],
      "requirements": ["Authority", "StateSnapshot", "LamportConservation", "InvariantCheck"]
    }
  ],
  "compatibility": {
    "pairs": [
      {
        "from": "Vault@1",
        "to": "Vault@2",
        "toVersion": 2,
        "policy": "append-only",
        "backwardReadable": true
      }
    ]
  }
}

Segment metadata in manifests

For segmented accounts, each segment entry includes:

Field Type Meaning
name string Segment identifier
role string Core / Extension / Journal / Index / Cache / Audit / Shard
segment_id hex FNV-1a hash of segment name
layout_ref string Layout name for this segment
required bool Must be present in every account instance
append_only bool Only append operations allowed
rebuildable bool Can be reconstructed from other data
immutable bool Cannot be modified after init

The Hopper IDL

Purpose

The Hopper IDL is a public-facing Hopper schema for:

  • TypeScript client generation
  • Kotlin, Python, and Rust client generation
  • External integrations
  • Hopper-aware tooling

It is not the Solana IDL v0.1.0 format.

File format

hopper.idl.json

This snippet follows the current IdlJsonFromManifest shape. It continues the same illustrative 0.2.1 fixture; the values are examples, not a release artifact.

Structure

{
  "name": "hopper_registry",
  "version": "0.2.1",
  "description": "Segmented registry example",
  "instructions": [
    {
      "name": "deposit",
      "tag": 1,
      "args": [
        { "name": "amount", "type": "u64", "size": 8, "encoding": "fixed" }
      ],
      "accounts": [
        { "name": "depositor", "writable": false, "signer": true },
        { "name": "vault", "writable": true, "signer": false, "layoutRef": "Vault" }
      ]
    }
  ],
  "accounts": [
    {
      "name": "Vault",
      "disc": 1,
      "version": 1,
      "layoutId": "a1b2c3d4e5f60718",
      "totalSize": 57,
      "fieldCount": 3,
      "fields": [
        { "name": "authority", "type": "[u8;32]", "size": 32, "offset": 16, "intent": "authority" },
        { "name": "balance", "type": "WireU64", "size": 8, "offset": 48, "intent": "balance" },
        { "name": "bump", "type": "u8", "size": 1, "offset": 56, "intent": "custom" }
      ],
      "semanticFingerprint": "0000000000000000000000000000000000000000000000000000000000000000"
    }
  ],
  "events": [
    {
      "name": "DepositEvent",
      "tag": 1,
      "fields": [
        { "name": "authority", "type": "[u8;32]", "size": 32, "offset": 0, "intent": "authority" },
        { "name": "amount", "type": "u64", "size": 8, "offset": 32, "intent": "balance" }
      ]
    }
  ],
  "fingerprints": [
    { "layoutId": "a1b2c3d4e5f60718", "name": "Vault" }
  ]
}

What IDL excludes

  • Migration planning data
  • Trust profile internals
  • Policy wiring details
  • Receipt render metadata
  • Unsafe invariant catalog
  • Segment migration hints

These live in the Manifest only.

Codama Compatibility

Hopper is Codama-compatible where it improves developer experience:

  • Client generation
  • Instruction/account metadata for explorers
  • TypeScript ecosystem interop

Hopper does not flatten its richer state model to fit Codama. The Manifest preserves full richness; Hopper IDL exposes the clean public subset; and the Codama projection is generated directly from the same ProgramManifest, not by round-tripping through Hopper IDL.

hopper schema export --manifest @hopper.manifest.json
hopper schema export --idl @hopper.manifest.json
hopper schema export --codama @hopper.manifest.json

Solana IDL v0.1.0 projection

Solana IDL is a separate, lossless-only interoperability target:

hopper schema export --anchor-idl @hopper.manifest.json \
  --program-id <PROGRAM_ID>

The projection preserves Hopper's instruction, account, and event discriminators. Account bodies declare custom hopper-zero-copy-v1 serialization, so generic Anchor-Borsh account decoders cannot decode Hopper state. Export fails closed on dynamic account tails, unsupported bounded wire encodings, remaining-account contracts, unresolved or unsafe PDA seeds, unresolved fixed addresses, and ambiguous discriminator prefixes.

hopper compile --emit idl emits Hopper IDL; it does not invoke this Solana IDL projection. hopper publish-idl validates the Solana projection before a dry run or live Program Metadata publication.

Generation Pipeline

Rust declarations (hopper_layout!, hopper_dispatch!, etc.)
    |
    v
Schema extraction (hopper-schema crate)
    |
    v
ProgramManifest
    |
    v
Rich manifest + 6 clients + Hopper IDL + Codama JSON
              + lossless-only Solana IDL v0.1.0
    |
    v
CLI / Manager / Planner / Receipts / external tooling

The extraction layer lives in hopper-schema. It reads LayoutManifest constants generated by macros and assembles them into the output formats. No runtime reflection. No dynamic discovery. Everything is compile-time deterministic.

File Layout

project/
  hopper.manifest.json    # Rich manifest (generated)
  hopper.idl.json         # Hopper public IDL (generated)
  hopper.codama.json      # Codama projection (generated)
  program.solana-idl.json # Optional validated Solana IDL v0.1.0 projection
  src/
    lib.rs                # Canonical code declarations
  docs/
    SCHEMA_ARCHITECTURE.md
    PROC_MACRO_POLICY.md