On-chain schema proposal
A clearly labeled design for future manifest pointers, separate from the shipped Program Metadata IDL path.
Status: design document. A HopperSchemaPointer data type exists in source, but
its PDA derivation, publication authority, hopper publish command, and Manager
--address discovery workflow are not implemented. It is not a shipped
on-chain discovery surface.
The shipped public-cluster path is narrower: hopper publish-idl projects a
local Hopper manifest into validated Solana IDL v0.1.0 JSON and writes that JSON
through the official Program Metadata program. The projection carries
instruction names, Hopper's actual instruction/account/event discriminators,
account roles, and arguments. Account bodies use custom
hopper-zero-copy-v1 serialization, so the IDL does not make Hopper accounts
Anchor-Borsh decodable.
Projection and publication fail closed on dynamic account tails, unsupported
bounded wire encodings, remaining-account contracts, unresolved or unsafe PDA
seeds, unresolved fixed addresses, and ambiguous discriminator prefixes. They
do not publish the Hopper manifest, declared byte ranges, or a Grillo effect
contract. A dry run
has no network access and sends nothing. Live publication defaults to devnet;
named Mainnet and every raw, custom, or SOLANA_RPC_URL endpoint require
confirmation unless --yes is supplied.
Shipped publication workflows
hopper publish-manifest publishes the normalized Hopper manifest through
Program Metadata under the custom hopper-manifest seed. It supports readback
and authority-baseline tooling. The seed is a Hopper convention, not a reserved
standard. hopper publish-idl publishes the supported Solana IDL projection.
Neither publication alone binds the declaration to the deployed ELF; use
release verification for that check. These workflows do not implement the
proposed HopperSchemaPointer account format described below.
Problem
Without on-chain schema, tools must obtain manifests out-of-band (via Git repos, package registries, or JSON files). On-chain publication enables program address → schema lookup.
Design
Truth Hierarchy
ProgramManifest ← rich internal truth (local / version control)
ProgramIdl ← public schema (published or stored off-chain)
CodamaProjection ← interop subset (for Codama/Kinobi tooling)
HopperSchemaPointer ← on-chain pointer to the above
The on-chain account stores hashes and URIs, not the full manifest. This keeps account size small and avoids rent-exempt bloat.
Proposed HopperSchemaPointer account
#[repr(C)]
pub struct HopperSchemaPointer {
// -- Hopper header (16 bytes) --
// disc: 255 (reserved discriminator for schema pointers)
// version: 1
// flags: 0x0001 (INITIALIZED)
// layout_id: sha256("hopper:v1:SchemaPointer:1:...")[..8]
// -- Payload --
pub schema_version: u16, // Schema format version (1)
pub pointer_flags: u16, // Feature flags (see below)
pub manifest_hash: [u8; 32], // SHA-256 of hopper.manifest.json
pub idl_hash: [u8; 32], // SHA-256 of hopper.idl.json
pub codama_hash: [u8; 32], // SHA-256 of hopper.codama.json
pub uri_len: u16, // Length of the URI string
pub uri: [u8; 192], // UTF-8 URI to the manifest
// Total payload: 2 + 2 + 32 + 32 + 32 + 2 + 192 = 294 bytes
// Total with header: 294 + 16 = 310 bytes
}
Pointer Flags
| Bit | Name | Description |
|---|---|---|
| 0 | FLAG_HAS_MANIFEST |
manifest_hash is populated |
| 1 | FLAG_HAS_IDL |
idl_hash is populated |
| 2 | FLAG_HAS_CODAMA |
codama_hash is populated |
| 3 | FLAG_HAS_URI |
uri contains a valid URI |
| 4 | FLAG_URI_IS_IPFS |
URI points to IPFS (content-addressed) |
| 5 | FLAG_URI_IS_ARWEAVE |
URI points to Arweave (permanent storage) |
Proposed account address derivation
The schema pointer account is at a deterministic PDA:
seeds = ["hopper-schema", program_id]
If implemented, this would let a client derive the pointer from a program ID.
URI Strategies
| Strategy | URI Format | Pros | Cons |
|---|---|---|---|
| IPFS | ipfs://Qm... |
Content-addressed, cheap | Needs pinning |
| Arweave | ar://... |
Permanent, no pinning | Costs AR |
| HTTPS | https://... |
Simple | Mutable, trust required |
| On-chain | hopper://account/... |
Fully on-chain | Expensive rent |
Recommended: IPFS for manifests (content-addressed, hash-verifiable), with the SHA-256 hash on-chain for integrity verification.
Proposed workflow
- Build:
hopper schema export --manifest @manifest.json > hopper.manifest.json - Hash:
sha256sum hopper.manifest.json - Upload: Pin to IPFS, Arweave, or host via HTTPS
- Publish (not implemented):
hopper publish --program <PROGRAM_ID> --manifest-hash <HASH> --uri <URI> - Discover (not implemented):
hopper manager summary --address <PROGRAM_ID>fetches schema pointer, downloads manifest, verifies hash, decodes program.
Manager Integration
Hopper Manager currently accepts @manifest.json for local files. The proposed
pointer workflow would add --address <PROGRAM_ID>:
# Local (current)
hopper manager summary @manifest.json
# Proposed; not implemented
hopper manager summary --address <PROGRAM_ID>
The proposed flow:
- Derive PDA from program ID
- Fetch
HopperSchemaPointeraccount data - Extract URI and manifest hash
- Fetch manifest from URI
- Verify SHA-256 matches on-chain hash
- Deserialize and use as
ProgramManifest
Security Considerations
- Hash verification: Always compare the fetched manifest's SHA-256
against the on-chain
manifest_hash. Reject mismatches. - Authority: Only the program's upgrade authority (or a designated schema authority) should be able to update the schema pointer.
- Immutability: Consider making the schema pointer non-closeable to prevent denial-of-service via account deletion.
Implementation Status
-
HopperSchemaPointertype defined inhopper-schema - Layout with
hopper_layout!macro - Spec document (this file)
- PDA derivation helper
- CLI
hopper publishcommand - Manager
--addressflag for on-chain lookup - IPFS upload integration
