Skip to main content

hopper/
lib.rs

1//! # Hopper
2//!
3//! Fast zero-copy Solana framework. Start with the familiar account/context
4//! facade, then opt into layout, segment, receipt, policy, migration, and
5//! schema modules only when the program needs them. Unsafe is available when
6//! you need it, and it is spelled `unsafe` so you can find it again.
7//!
8//! The goals, in priority order:
9//!
10//! 1. **Safety by default.** Every account byte you touch has been
11//!    owner-checked, signer-checked, layout-checked, and borrow-checked
12//!    before you see it. Unsafe is an opt-in escape hatch, never a
13//!    default.
14//! 2. **Low-overhead performance.** Account data points directly at
15//!    the runtime input region. No deserialization pass, no heap
16//!    allocation, no hidden format machinery. If it costs compute, it
17//!    is because you asked for it.
18//! 3. **Framework-grade ergonomics.** `#[hopper::account]`,
19//!    `#[hopper::accounts]`, `#[hopper::program]`, typed wrappers such as
20//!    `Account<'info, T>` and `Signer<'info>`, and the facade modules under
21//!    `hopper::{account, cpi, token, system}` keep the beginner surface small.
22//! 4. **Schema that travels.** Every layout, instruction, event, and
23//!    error is emitted as inspectable compile-time metadata. Off-chain
24//!    SDKs, IDLs, client generators, and diff tools consume it without
25//!    parsing source.
26//!
27//! ## Layers
28//!
29//! - `hopper::prelude`: beginner and migration path. Same runtime, clean import
30//!   story.
31//! - `hopper::{account, context, cpi, system, token, associated_token, memo}`:
32//!   everyday program modules.
33//! - `hopper::{layout, segment, receipt, migration, interface, schema, policy}`:
34//!   systems-mode modules for layout evolution, field leasing, manifests, and
35//!   audited escape hatches.
36//! - `hopper::substrate`: raw Hopper Runtime and Hopper Native building blocks
37//!   for programs that want Pinocchio-class control with Hopper's account and
38//!   wire contracts still visible.
39//! - `hopper::internal`: explicit lower-crate escape hatch.
40//!
41//! ## Crate map
42//!
43//! - `hopper_core`: wire types, account header, segment maps, validation,
44//!   collections, and opt-in advanced subsystems (frame, receipt, policy,
45//!   diff, migration) behind feature gates.
46//! - `hopper_runtime`: the runtime surface a program actually calls.
47//!   Context, Account, Pod, guards, CPI, migrations, log macros,
48//!   entrypoint bridges.
49//! - `hopper_macros`: declarative macros. `hopper_layout!`, `hopper_check!`,
50//!   `hopper_error!`, `hopper_init!`, `hopper_close!`, `hopper_require!`,
51//!   `hopper_register_discs!`, `hopper_verify_pda!`, `hopper_invariant!`,
52//!   `hopper_manifest!`, `hopper_segment!`, `hopper_validate!`,
53//!   `hopper_virtual!`, `hopper_interface!`, `hopper_accounts!`,
54//!   `hopper_assert_compatible!`, `hopper_assert_fingerprint!`, and
55//!   `const_assert_pod!`.
56//! - `hopper_derive` (`hopper-derive` package): proc-macro DX layer.
57//!   `#[hopper::state]`, `#[hopper::pod]`, `#[hopper::context]`,
58//!   `#[derive(Accounts)]`, `#[hopper::program]`, `#[hopper::migrate]`,
59//!   `#[hopper::args]`, `#[hopper::error]`, `#[hopper::event]`,
60//!   `#[hopper::constant]`, `#[hopper::crank]`, `hopper::declare_program!`,
61//!   `#[hopper::dynamic]`, and `#[hopper::dynamic_account]`.
62//! - `hopper_solana`: SPL Token/Mint readers, Token-2022 checks, CPI
63//!   guards, Pyth oracle, TWAP, Ed25519/Merkle crypto, authority rotation.
64//! - `hopper_system`: System Program instruction builders.
65//! - `hopper_token`: SPL Token instruction builders.
66//! - `hopper_token_2022`: Token-2022 instruction builders plus extension
67//!   screening helpers.
68//! - `hopper_associated_token`: ATA derivation and instruction builders.
69//! - `hopper_schema`: layout manifests, fingerprinting, field-level
70//!   diffing, compatibility verdicts, Codama/IDL projections, client
71//!   generation.
72//!
73//! ## Access model
74//!
75//! Four reads, one rule: safety first, unsafe by name.
76//!
77//! ```text
78//! Safe full:    account.load::<T>()        / account.load_mut::<T>()
79//! Safe segment: ctx.segment_ref::<T>(i,o)  / ctx.segment_mut::<T>(i,o)
80//! Explicit raw: unsafe { account.raw_ref() / account.raw_mut() }
81//! Cross-prog:   account.load_cross_program::<T>()
82//! ```
83//!
84//! `load` and `segment_ref` are the defaults. `raw_ref` is the escape
85//! hatch. `load_cross_program` is the Hopper-specific verb for reading
86//! an account owned by another program (foreign-ownership checked at
87//! the type level).
88//!
89//! ## Quick start
90//!
91//! Declare an account layout, bind it in a context, ship a handler.
92//!
93//! ```ignore
94//! use hopper::prelude::*;
95//!
96//! #[account(disc = 1, version = 1)]
97//! #[repr(C)]
98//! #[derive(Clone, Copy)]
99//! pub struct Vault {
100//!     pub authority: Address,
101//!     pub balance: WireU64,
102//!     pub bump: u8,
103//! }
104//! ```
105//!
106//! `Vault` is now a zero-copy account layout with a Hopper header, layout
107//! fingerprint, schema metadata, and typed `Account<'info, Vault>` access. No
108//! Borsh pass, no hidden writeback pass.
109
110#![no_std]
111#![deny(unsafe_op_in_unsafe_fn)]
112
113#[cfg(any(
114    all(feature = "hopper-native-backend", feature = "legacy-pinocchio-compat"),
115    all(feature = "hopper-native-backend", feature = "solana-program-backend"),
116    all(
117        feature = "legacy-pinocchio-compat",
118        feature = "solana-program-backend"
119    ),
120))]
121compile_error!("Enable exactly one Hopper backend: hopper-native-backend, legacy-pinocchio-compat, or solana-program-backend.");
122
123// ── Hopper Lang modules ──────────────────────────────────────────────
124
125#[doc(hidden)]
126pub mod __macro_support;
127pub mod guards;
128pub mod pda;
129pub mod prelude;
130pub mod receipts;
131
132// Re-export crates
133pub use hopper_associated_token;
134pub use hopper_core;
135pub use hopper_runtime;
136pub use hopper_schema;
137pub use hopper_solana;
138pub use hopper_system;
139pub use hopper_token;
140pub use hopper_token_2022;
141
142/// Beginner-facing account surface.
143///
144/// This module is the framework-first import path for account roles and typed
145/// account access. The lower-level crates remain available, but normal program
146/// authors should be able to stay inside `hopper::prelude::*` and these facade
147/// modules.
148pub mod account {
149    pub use hopper_core::abi::{
150        Authority, Mint, Token, TokenAccount, TypedAddress, UntypedAddress,
151    };
152    pub use hopper_core::accounts::{
153        HopperAccount, HopperAccounts, HopperCtx, HopperIx, ProgramAccount, ProgramRef,
154        SegmentedAccount, SignerAccount, ValidateAccount,
155    };
156    pub use hopper_runtime::{
157        Account, AccountView, HopperSigner as Signer, InitAccount, Interface, InterfaceAccount,
158        InterfaceAccountLayout, InterfaceAccountResolve, InterfaceSpec, Program, ProgramId,
159        SystemAccount, SystemId, UncheckedAccount,
160    };
161
162    /// Anchor-style spelling for the System Program marker.
163    pub type System = SystemId;
164}
165
166/// Typed instruction context and account-binding helpers.
167pub mod context {
168    pub use hopper_core::accounts::{hopper_entry, HopperAccounts, HopperCtx, HopperIx};
169    pub use hopper_runtime::Context;
170}
171
172/// Cross-program invocation helpers and generated instruction parts.
173pub mod cpi {
174    pub use hopper_core::cpi::*;
175    pub use hopper_runtime::cpi::{
176        invoke, invoke_signed, invoke_signed_unchecked, invoke_signed_with_bounds,
177        invoke_unchecked, invoke_with_bounds, set_return_data, MAX_CPI_ACCOUNTS, MAX_RETURN_DATA,
178        MAX_STATIC_CPI_ACCOUNTS,
179    };
180    pub use hopper_runtime::{CpiAccount, InstructionAccount, InstructionView, Seed, Signer};
181}
182
183/// System Program helpers.
184#[allow(unused_imports)]
185pub mod system {
186    pub use hopper_system::instructions::*;
187    pub use hopper_system::SYSTEM_PROGRAM_ID;
188    pub use hopper_system::*;
189}
190
191/// SPL Token helpers.
192#[allow(ambiguous_glob_reexports, unused_imports)]
193pub mod token {
194    pub use hopper_runtime::token::*;
195    pub use hopper_solana::interface::{
196        interface_transfer_checked, interface_transfer_checked_signed, InterfaceMint,
197        InterfaceTokenAccount, TokenProgramKind,
198    };
199    pub use hopper_token::instructions::*;
200    pub use hopper_token::TOKEN_PROGRAM_ID;
201    pub use hopper_token::*;
202}
203
204/// SPL Token-2022 helpers.
205#[allow(ambiguous_glob_reexports, unused_imports)]
206pub mod token_2022 {
207    pub use hopper_runtime::token_2022_ext::*;
208    pub use hopper_token_2022::instructions::*;
209    pub use hopper_token_2022::TOKEN_2022_PROGRAM_ID;
210    pub use hopper_token_2022::*;
211}
212
213/// Associated Token Account helpers.
214#[allow(unused_imports)]
215pub mod associated_token {
216    pub use hopper_associated_token::instructions::*;
217    pub use hopper_associated_token::ATA_PROGRAM_ID;
218    pub use hopper_associated_token::*;
219}
220
221/// SPL Memo helper surface.
222pub mod memo {
223    pub use hopper_memo::*;
224}
225
226/// Event and log helpers.
227pub mod events {
228    pub use crate::receipts::{emit_receipt, emit_tagged_receipt, emit_typed_receipt, Receipt};
229    #[cfg(feature = "cpi")]
230    pub use hopper_core::event::emit_event_cpi;
231    pub use hopper_core::event::{emit_event, emit_event_tagged, emit_slices};
232    pub use hopper_runtime::{hopper_emit_cpi, hopper_log, msg};
233}
234
235/// Advanced layout and header surface.
236pub mod layout {
237    pub use hopper_core::abi::{FingerprintTransition, LayoutFingerprint, WireType};
238    pub use hopper_core::account::{
239        check_header, read_discriminator, read_header_flags, read_layout_id, read_version,
240        write_header, AccountHeader, AccountReader, FixedLayout, HEADER_FORMAT, HEADER_LEN,
241    };
242    pub use hopper_core::field_map::{FieldInfo, FieldMap};
243    pub use hopper_runtime::layout::{init_header, HopperHeader, LayoutContract, LayoutInfo};
244    pub use hopper_runtime::{AccountLayout, Pod, WireLayout, ZeroCopy};
245}
246
247/// Advanced segment and field-lease surface.
248pub mod segment {
249    pub use hopper_core::account::segment_role::{
250        SegmentRole, SEG_ROLE_AUDIT, SEG_ROLE_CACHE, SEG_ROLE_CORE, SEG_ROLE_EXTENSION,
251        SEG_ROLE_INDEX, SEG_ROLE_JOURNAL, SEG_ROLE_SHARD,
252    };
253    pub use hopper_core::account::{
254        segment_id, SegmentDescriptor, SegmentEntry, SegmentId, SegmentRegistry,
255        SegmentRegistryMut, SegmentSlice, SegmentSliceMut, SegmentTable, SegmentTableMut,
256        MAX_REGISTRY_SEGMENTS, MAX_SEGMENTS, REGISTRY_HEADER_SIZE, REGISTRY_OFFSET,
257        SEGMENT_DESC_SIZE, SEGMENT_ENTRY_SIZE, SEG_FLAG_DYNAMIC, SEG_FLAG_FROZEN, SEG_FLAG_LOCKED,
258    };
259    pub use hopper_core::segment_map::{assert_segment_field_alignment, SegmentMap, StaticSegment};
260    pub use hopper_runtime::{
261        AccessKind, FieldCapability, Ref, RefMut, SegRef, SegRefMut, Segment, SegmentBorrow,
262        SegmentBorrowGuard, SegmentBorrowRegistry, SegmentLease, TypedSegment,
263        FIELD_POLICY_AUTHORITY_GATED, FIELD_POLICY_CHECKED_MATH, FIELD_POLICY_IMMUTABLE_AFTER_INIT,
264        FIELD_ROLE_AUTHORITY, FIELD_ROLE_BALANCE, FIELD_ROLE_DATA, FIELD_ROLE_VERSION,
265    };
266}
267
268/// Receipt helpers and receipt wire types.
269pub mod receipt {
270    pub use crate::receipts::{emit_receipt, emit_tagged_receipt, emit_typed_receipt, Receipt};
271    #[cfg(feature = "receipt")]
272    pub use hopper_core::receipt::*;
273}
274
275/// Layout migration helpers.
276pub mod migration {
277    #[cfg(feature = "migrate")]
278    pub use hopper_core::migrate::*;
279    pub use hopper_runtime::{apply_pending_migrations, LayoutMigration, MigrationEdge};
280}
281
282/// Cross-program layout/interface pinning helpers.
283pub mod interface {
284    pub use hopper_runtime::{
285        ForeignLens, ForeignManifest, Interface, InterfaceAccount, InterfaceAccountLayout,
286        InterfaceAccountResolve, InterfaceSpec, TransparentAddress,
287    };
288    pub use hopper_solana::interface::*;
289}
290
291/// Schema, manifest, and IDL projection surface.
292pub mod schema {
293    pub use hopper_schema::*;
294}
295
296/// Policy engine surface for systems-mode programs.
297pub mod policy {
298    #[cfg(feature = "policy")]
299    pub use hopper_core::policy::*;
300    pub use hopper_runtime::{HopperInstructionPolicy, HopperProgramPolicy, HopperProgramProfile};
301}
302
303/// Protocol-grade Hopper surface.
304///
305/// Import this when a program deliberately reaches beyond framework mode into
306/// layout contracts, segment registries, receipts, policies, migrations,
307/// manifests, overlays, or cross-program interface pinning.
308#[allow(ambiguous_glob_reexports, unused_imports)]
309pub mod systems {
310    pub use crate::interface::*;
311    pub use crate::layout::*;
312    pub use crate::migration::*;
313    pub use crate::policy::*;
314    pub use crate::receipt::*;
315    pub use crate::schema::*;
316    pub use crate::segment::*;
317    pub use crate::{interface, layout, migration, policy, receipt, schema, segment};
318
319    pub use hopper_core::account::{
320        overlay, overlay_mut, read_dynamic_u16, read_dynamic_u32, read_dynamic_u8, safe_close,
321        safe_close_with_sentinel, safe_realloc, write_dynamic_u16, write_dynamic_u32,
322        write_dynamic_u8, DynamicView, DynamicViewMut, ReallocGuard, VerifiedAccount,
323        VerifiedAccountMut, CLOSE_SENTINEL,
324    };
325    pub use hopper_core::check::{find_and_verify_pda, rent_exempt_min};
326    pub use hopper_core::prelude_advanced::*;
327    pub use hopper_core::prelude_core::*;
328    pub use hopper_runtime::{
329        fast_entrypoint, hopper_entrypoint, hopper_fast_entrypoint, hopper_lazy_entrypoint,
330        lazy_entrypoint, no_allocator, nostd_panic_handler, program_entrypoint, AccountProof,
331        BoundedString, BoundedVec, CpiAccount, ExecutableChecked, HasOneChecked, HopperString,
332        HopperVec, InstructionAccount, InstructionView, LayoutChecked, OwnerChecked, Seed,
333        SeedsChecked, SignerChecked, TailCodec, TailElement, TokenExtensionsChecked, Unchecked,
334        WritableChecked,
335    };
336
337    pub use crate::{
338        const_assert_pod, hopper_accounts, hopper_assert_compatible, hopper_assert_fingerprint,
339        hopper_check, hopper_close, hopper_dynamic_fields, hopper_dynamic_tail, hopper_error,
340        hopper_init, hopper_interface, hopper_invariant, hopper_layout, hopper_load,
341        hopper_manifest, hopper_register_discs, hopper_require, hopper_segment, hopper_validate,
342        hopper_verify_pda, hopper_virtual, layout_migrations,
343    };
344
345    #[cfg(feature = "proc-macros")]
346    pub use crate::{args, declare_program, dynamic, migrate, pod, state};
347}
348
349/// Sovereign substrate surface.
350///
351/// This is the lowest public layer for programs that want direct account,
352/// syscall, PDA, hashing, memory, budget, and raw-entrypoint tools while still
353/// staying inside Hopper's crate graph. Framework-mode code should prefer
354/// `hopper::prelude::*`; systems-mode code should prefer `hopper::systems::*`.
355#[allow(ambiguous_glob_reexports, unused_imports)]
356pub mod substrate {
357    pub use hopper_runtime::{
358        AccountView, Address, CpiAccount, InstructionAccount, InstructionView, ProgramError,
359        ProgramResult, Ref, RefMut, Seed, Signer, SUCCESS,
360    };
361
362    #[cfg(feature = "hopper-native-backend")]
363    pub use hopper_runtime::__hopper_native::{
364        account_view, address, batch, budget, capability, entrypoint, error, hash, introspect,
365        lazy, lens, log, mem, pda, pod, raw, raw_account, raw_input, return_data, safe, syscalls,
366        sysvar, verify, wire, AccountView as NativeAccountView, Address as NativeAddress, CuBudget,
367        DataFingerprint, LamportSnapshot, ReturnData,
368    };
369
370    #[cfg(feature = "hopper-native-backend")]
371    pub use hopper_runtime::__hopper_native::{
372        find_bump_for_address, read_bump_from_account, verify_pda_from_stored_bump,
373        verify_pda_strict, RuntimeAccount,
374    };
375}
376
377/// First-party DeFi math helpers. Enable with `features = ["finance"]`.
378#[cfg(feature = "finance")]
379pub mod finance {
380    pub use hopper_finance::*;
381}
382
383/// First-party lending helpers. Enable with `features = ["lending"]`.
384#[cfg(feature = "lending")]
385pub mod lending {
386    pub use hopper_lending::*;
387}
388
389/// First-party staking helpers. Enable with `features = ["staking"]`.
390#[cfg(feature = "staking")]
391pub mod staking {
392    pub use hopper_staking::*;
393}
394
395/// First-party vesting helpers. Enable with `features = ["vesting"]`.
396#[cfg(feature = "vesting")]
397pub mod vesting {
398    pub use hopper_vesting::*;
399}
400
401/// First-party distribution helpers. Enable with `features = ["distribute"]`.
402#[cfg(feature = "distribute")]
403pub mod distribute {
404    pub use hopper_distribute::*;
405}
406
407/// First-party multisig helpers. Enable with `features = ["multisig"]`.
408#[cfg(feature = "multisig")]
409pub mod multisig {
410    pub use hopper_multisig::*;
411}
412
413/// Anchor interop helpers. Enable with `features = ["anchor-interop"]`.
414#[cfg(feature = "anchor-interop")]
415pub mod anchor {
416    pub use hopper_anchor::*;
417}
418
419/// Explicit escape hatch for lower layers. Normal programs should not need it.
420#[doc(hidden)]
421pub mod internal {
422    pub use crate::{hopper_core, hopper_runtime, hopper_schema, hopper_solana};
423}
424
425/// Optional Metaplex Token Metadata builders. Behind `--features metaplex`.
426/// Reach for this via `hopper::hopper_metaplex::CreateMetadataAccountV3`,
427/// `CreateMasterEditionV3`, `UpdateMetadataAccountV2`, plus the
428/// `metadata_pda` / `master_edition_pda` PDA helpers.
429#[cfg(feature = "metaplex")]
430pub use hopper_metaplex;
431
432/// Small utilities. Re-exported at the crate root so `use hopper::utils::hint::likely;`
433/// just works.
434pub use hopper_runtime::utils;
435
436// Re-export macros at the crate root
437pub use hopper_core::hopper_dispatch;
438pub use hopper_macros::{
439    const_assert_pod, hopper_accounts, hopper_assert_compatible, hopper_assert_fingerprint,
440    hopper_check, hopper_close, hopper_error, hopper_init, hopper_interface, hopper_invariant,
441    hopper_layout, hopper_manifest, hopper_register_discs, hopper_require, hopper_segment,
442    hopper_validate, hopper_verify_pda, hopper_virtual,
443};
444
445// Audit I4: schema-epoch migration chain composition. `#[macro_export]`
446// macros are always anchored at the defining crate's root, so the
447// user-facing path `hopper::layout_migrations!` requires an explicit
448// re-export here.
449pub use hopper_runtime::layout_migrations;
450
451/// Destructuring sugar for raw-dispatch handlers.
452///
453/// Replaces the common pattern:
454///
455/// ```ignore
456/// let [user, vault, system_program, ..] = accounts else {
457///     return Err(ProgramError::NotEnoughAccountKeys);
458/// };
459/// ```
460///
461/// with the tighter form:
462///
463/// ```ignore
464/// hopper_load!(accounts => [user, vault, system_program]);
465/// ```
466///
467/// The bindings are plain `&AccountView` references (not owned values),
468/// matching the destructuring pattern. A trailing `..` is accepted and
469/// discards any extra accounts. The macro bails with
470/// `ProgramError::NotEnoughAccountKeys` when the slice is too short,
471/// mirroring Hopper's existing idiom.
472///
473/// Use this in the raw-dispatch authoring style (no `#[hopper::context]`).
474/// The proc-macro context already binds accounts by name, so this is only
475/// useful when you are working with `&[AccountView]` directly - typically
476/// inside `fn process_instruction(_, accounts: &[AccountView], _)` before
477/// routing to per-variant handlers.
478///
479/// ## Examples
480///
481/// ```ignore
482/// fn process_deposit(
483///     program_id: &Address,
484///     accounts: &[AccountView],
485///     data: &[u8],
486/// ) -> ProgramResult {
487///     hopper_load!(accounts => [user, vault, system_program]);
488///     user.require_signer()?;
489///     vault.require_writable()?;
490///     // ... rest of handler ...
491///     Ok(())
492/// }
493/// ```
494///
495/// With a trailing rest pattern (accept more accounts, ignore them):
496///
497/// ```ignore
498/// hopper_load!(accounts => [user, vault, ..]);
499/// ```
500///
501/// The trailing `..` is redundant with the default behaviour (the macro
502/// always accepts more accounts than declared) but is supported for
503/// stylistic parity with the native Rust slice pattern.
504#[macro_export]
505macro_rules! hopper_load {
506    ( $slice:expr => [ $($binding:ident),+ $(, ..)? $(,)? ] ) => {
507        let [ $($binding,)+ .. ] = $slice else {
508            return ::core::result::Result::Err(
509                $crate::hopper_runtime::error::ProgramError::NotEnoughAccountKeys,
510            );
511        };
512    };
513}
514
515/// Declare a dynamic-tail payload with bounded dynamic fields.
516///
517/// The generated type implements `TailCodec`, so it can be used directly with
518/// `#[hopper::state(dynamic_tail = MyTail)]`. Fields are encoded in declaration
519/// order. Use `HopperString<N>` for bounded UTF-8 strings and
520/// `HopperVec<T, N>` for bounded element lists. The longer
521/// `BoundedString<N>` and `BoundedVec<T, N>` names remain available when a
522/// protocol wants the storage tradeoff to be explicit in source. For
523/// Quasar-shaped account syntax, prefer `#[hopper::dynamic_account]`; use this
524/// macro when you want an explicit custom `TailCodec` payload.
525///
526/// ```ignore
527/// hopper::hopper_dynamic_tail! {
528///     pub struct MultisigTail {
529///         label: HopperString<32>,
530///         signers: HopperVec<Address, 10>,
531///     }
532/// }
533/// ```
534#[macro_export]
535macro_rules! hopper_dynamic_tail {
536    (
537        $(#[$meta:meta])*
538        $vis:vis struct $name:ident {
539            $( $field:ident : $ty:ty ),* $(,)?
540        }
541    ) => {
542        $(#[$meta])*
543        #[derive(Clone, Copy, Default)]
544        $vis struct $name {
545            $( pub $field: $ty, )*
546        }
547
548        impl $crate::__runtime::TailCodec for $name {
549            const MAX_ENCODED_LEN: usize = 0 $(+ <$ty as $crate::__runtime::TailCodec>::MAX_ENCODED_LEN)*;
550
551            #[inline]
552            fn encode(
553                &self,
554                out: &mut [u8],
555            ) -> ::core::result::Result<usize, $crate::__runtime::ProgramError> {
556                let mut cursor = 0usize;
557                $(
558                    let written = <$ty as $crate::__runtime::TailCodec>::encode(
559                        &self.$field,
560                        &mut out[cursor..],
561                    )?;
562                    cursor = cursor
563                        .checked_add(written)
564                        .ok_or($crate::__runtime::ProgramError::AccountDataTooSmall)?;
565                )*
566                Ok(cursor)
567            }
568
569            #[inline]
570            fn decode(
571                input: &[u8],
572            ) -> ::core::result::Result<(Self, usize), $crate::__runtime::ProgramError> {
573                let mut cursor = 0usize;
574                $(
575                    let ($field, consumed) = <$ty as $crate::__runtime::TailCodec>::decode(
576                        &input[cursor..],
577                    )?;
578                    cursor = cursor
579                        .checked_add(consumed)
580                        .ok_or($crate::__runtime::ProgramError::InvalidAccountData)?;
581                )*
582                Ok((Self { $( $field, )* }, cursor))
583            }
584        }
585    };
586}
587
588#[doc(hidden)]
589#[macro_export]
590macro_rules! __hopper_dynamic_fields_tail {
591    (@emit [$($meta:tt)*] [$vis:vis] [$name:ident] [$($fields:tt)*]) => {
592        $crate::hopper_dynamic_tail! {
593            $($meta)*
594            $vis struct $name {
595                $($fields)*
596            }
597        }
598    };
599
600    (@parse [$($meta:tt)*] [$vis:vis] [$name:ident] [$($fields:tt)*]) => {
601        $crate::__hopper_dynamic_fields_tail!(@emit [$($meta)*] [$vis] [$name] [$($fields)*]);
602    };
603    (@parse [$($meta:tt)*] [$vis:vis] [$name:ident] [$($fields:tt)*] ,) => {
604        $crate::__hopper_dynamic_fields_tail!(@emit [$($meta)*] [$vis] [$name] [$($fields)*]);
605    };
606
607    (@parse [$($meta:tt)*] [$vis:vis] [$name:ident] [$($fields:tt)*]
608        $field:ident : string < $cap:literal >, $($rest:tt)+
609    ) => {
610        $crate::__hopper_dynamic_fields_tail!(@parse [$($meta)*] [$vis] [$name]
611            [$($fields)* $field: $crate::__runtime::HopperString<$cap>,]
612            $($rest)+
613        );
614    };
615    (@parse [$($meta:tt)*] [$vis:vis] [$name:ident] [$($fields:tt)*]
616        $field:ident : string < $cap:literal > $(,)?
617    ) => {
618        $crate::__hopper_dynamic_fields_tail!(@emit [$($meta)*] [$vis] [$name]
619            [$($fields)* $field: $crate::__runtime::HopperString<$cap>,]
620        );
621    };
622
623    (@parse [$($meta:tt)*] [$vis:vis] [$name:ident] [$($fields:tt)*]
624        $field:ident : vec < $ty:ty, $cap:literal >, $($rest:tt)+
625    ) => {
626        $crate::__hopper_dynamic_fields_tail!(@parse [$($meta)*] [$vis] [$name]
627            [$($fields)* $field: $crate::__runtime::HopperVec<$ty, $cap>,]
628            $($rest)+
629        );
630    };
631    (@parse [$($meta:tt)*] [$vis:vis] [$name:ident] [$($fields:tt)*]
632        $field:ident : vec < $ty:ty, $cap:literal > $(,)?
633    ) => {
634        $crate::__hopper_dynamic_fields_tail!(@emit [$($meta)*] [$vis] [$name]
635            [$($fields)* $field: $crate::__runtime::HopperVec<$ty, $cap>,]
636        );
637    };
638
639    (@parse [$($meta:tt)*] [$vis:vis] [$name:ident] [$($fields:tt)*]
640        $field:ident : $ty:ty, $($rest:tt)+
641    ) => {
642        $crate::__hopper_dynamic_fields_tail!(@parse [$($meta)*] [$vis] [$name]
643            [$($fields)* $field: $ty,]
644            $($rest)+
645        );
646    };
647    (@parse [$($meta:tt)*] [$vis:vis] [$name:ident] [$($fields:tt)*]
648        $field:ident : $ty:ty $(,)?
649    ) => {
650        $crate::__hopper_dynamic_fields_tail!(@emit [$($meta)*] [$vis] [$name]
651            [$($fields)* $field: $ty,]
652        );
653    };
654}
655
656/// Explicit sugar for declaring bounded dynamic-tail fields.
657///
658/// This is a small front end over `hopper_dynamic_tail!`. It keeps Hopper's
659/// explicit fixed-body plus encoded-tail model, while letting ported programs
660/// spell custom tail fields as `string<N>` and `vec<T, N>`. For a full account
661/// declaration with inline tail fields, use `#[hopper::dynamic_account]`.
662///
663/// ```ignore
664/// hopper::hopper_dynamic_fields! {
665///     pub struct MultisigTail {
666///         label: string<32>,
667///         signers: vec<Address, 10>,
668///         nonce: u32,
669///     }
670/// }
671/// ```
672#[macro_export]
673macro_rules! hopper_dynamic_fields {
674    (
675        $(#[$meta:meta])*
676        $vis:vis struct $name:ident {
677            $($body:tt)*
678        }
679    ) => {
680        $crate::__hopper_dynamic_fields_tail!(@parse [$(#[$meta])*] [$vis] [$name] [] $($body)*);
681    };
682}
683
684// Ergonomic guard macros (the "winning architecture" design's
685// Jiminy-replacement safety layer). All are `#[macro_export]` from
686// hopper_runtime and are re-exported here so programs see them at
687// the top-level `hopper::*` path without needing to reach through
688// `hopper_runtime::`.
689pub use hopper_runtime::{
690    address, err, error, fast_entrypoint, hopper_emit_cpi, hopper_entrypoint,
691    hopper_fast_entrypoint, hopper_lazy_entrypoint, hopper_log, hopper_unsafe_region,
692    lazy_entrypoint, msg, no_allocator, nostd_panic_handler, program_entrypoint, require,
693    require_eq, require_gt, require_gte, require_keys_eq, require_keys_neq, require_lt,
694    require_lte, require_neq,
695};
696
697/// Declare a bounded multi-layout interface account resolver.
698///
699/// Use this when one account slot may hold one of several Hopper-header layouts
700/// owned by the same interface program set, such as a migration reader that
701/// accepts `VaultV1` or `VaultV2`.
702///
703/// ```ignore
704/// hopper::interface_account_set! {
705///     pub struct AnyVaultAccount: VaultPrograms;
706///     pub enum AnyVault {
707///         V1(VaultV1),
708///         V2(VaultV2),
709///     }
710/// }
711/// ```
712#[macro_export]
713macro_rules! interface_account_set {
714    (
715        $(#[$marker_meta:meta])*
716        $vis:vis struct $marker:ident : $interface:ty;
717        $(#[$resolved_meta:meta])*
718        $enum_vis:vis enum $resolved:ident {
719            $($variant:ident($layout:ty)),+ $(,)?
720        }
721    ) => {
722        $(#[$marker_meta])*
723        #[derive(Clone, Copy, Debug, Default)]
724        $vis struct $marker;
725
726        impl $crate::__runtime::FieldMap for $marker {
727            const FIELDS: &'static [$crate::__runtime::FieldInfo] = &[];
728        }
729
730        impl $crate::__runtime::LayoutContract for $marker {
731            const DISC: u8 = 0;
732            const VERSION: u8 = 0;
733            const LAYOUT_ID: [u8; 8] = [0; 8];
734            const SIZE: usize = $crate::__runtime::HopperHeader::SIZE;
735        }
736
737        impl $crate::__runtime::InterfaceAccountLayout for $marker {
738            type Interface = $interface;
739
740            #[inline]
741            fn validate_interface_account(
742                view: &$crate::__runtime::AccountView,
743            ) -> ::core::result::Result<(), $crate::__runtime::ProgramError> {
744                let data = view.try_borrow()?;
745                let info = $crate::__runtime::LayoutInfo::from_data(&data)
746                    .ok_or($crate::__runtime::ProgramError::AccountDataTooSmall)?;
747                if false $(|| info.matches::<$layout>())+ {
748                    Ok(())
749                } else {
750                    Err($crate::__runtime::ProgramError::InvalidAccountData)
751                }
752            }
753        }
754
755        $(#[$resolved_meta])*
756        $enum_vis enum $resolved<'a> {
757            $($variant($crate::__runtime::Ref<'a, $layout>)),+
758        }
759
760        impl $crate::__runtime::InterfaceAccountResolve for $marker {
761            type Resolved<'a> = $resolved<'a>;
762
763            #[inline]
764            fn resolve<'a>(
765                view: &'a $crate::__runtime::AccountView,
766            ) -> ::core::result::Result<Self::Resolved<'a>, $crate::__runtime::ProgramError> {
767                let info = {
768                    let data = view.try_borrow()?;
769                    $crate::__runtime::LayoutInfo::from_data(&data)
770                        .ok_or($crate::__runtime::ProgramError::AccountDataTooSmall)?
771                };
772                $(
773                    if info.matches::<$layout>() {
774                        return Ok($resolved::$variant(view.load_cross_program::<$layout>()?));
775                    }
776                )+
777                Err($crate::__runtime::ProgramError::InvalidAccountData)
778            }
779        }
780    };
781}
782
783/// Generate the small runtime bridge for a `#[program(entrypoint = false)]`
784/// module.
785///
786/// New programs do not need this macro: `#[program]` emits the same audited
787/// Hopper entrypoint bridge automatically. Keep `program_dispatch!` for
788/// compatibility and for unusual crates that intentionally disable the
789/// automatic bridge.
790///
791/// ```ignore
792/// #[program(entrypoint = false)]
793/// mod counter_program {
794///     // handlers
795/// }
796///
797/// hopper::program_dispatch!(counter_program);
798/// ```
799#[macro_export]
800macro_rules! program_dispatch {
801    ($program_mod:ident) => {
802        #[cfg(target_os = "solana")]
803        $crate::program_entrypoint!(__hopper_process_instruction);
804
805        #[doc(hidden)]
806        fn __hopper_process_instruction(
807            program_id: &$crate::__runtime::Address,
808            accounts: &[$crate::__runtime::AccountView],
809            instruction_data: &[u8],
810        ) -> ::core::result::Result<(), $crate::__runtime::ProgramError> {
811            let mut ctx = $crate::prelude::Context::new(program_id, accounts, instruction_data);
812            $program_mod::process_instruction(&mut ctx)
813        }
814    };
815}
816
817// Optional proc macro re-exports (enabled with `proc-macros` feature)
818#[cfg(feature = "proc-macros")]
819pub use hopper_macros_proc::{
820    account, accounts, args, constant, context, crank, declare_program, dynamic, dynamic_account,
821    error as error_code, event, hopper_args, hopper_constant, hopper_context, hopper_crank,
822    hopper_dynamic, hopper_dynamic_account, hopper_event, hopper_migrate, hopper_pod,
823    hopper_program, hopper_state, migrate, pod, program, state, Accounts, HopperInitSpace,
824};
825
826// Private re-export for generated code to reference runtime types
827#[doc(hidden)]
828pub mod __runtime {
829    pub use hopper_runtime::token_2022_ext;
830    pub use hopper_runtime::{
831        apply_pending_migrations, borrow_address_slice, borrow_bounded_str, read_tail,
832        read_tail_len, tail_capacity, tail_payload, write_tail, Account, AccountLayout,
833        AccountView, Address, BoundedString, BoundedVec, Context, FieldInfo, FieldMap,
834        HopperHeader, HopperInstructionPolicy, HopperProgramPolicy, HopperProgramProfile,
835        HopperSigner, HopperString, HopperVec, InitAccount, InstructionAccount, InstructionView,
836        Interface, InterfaceAccount, InterfaceAccountLayout, InterfaceAccountResolve,
837        InterfaceSpec, LayoutContract, LayoutInfo, LayoutMigration, MigrationEdge, Pod, Program,
838        ProgramError, ProgramId, Ref, RefMut, SegRef, SegRefMut, SegmentLease, SystemAccount,
839        SystemId, TailCodec, TailElement, UncheckedAccount,
840    };
841
842    // Crank marker type plus dynamic-CPI builder, emitted by
843    // `#[hopper::crank]` and by hand-written programs that need
844    // variable-length CPIs respectively. Exposed through this
845    // doc-hidden module so user code never reaches into
846    // `hopper_runtime::*` directly.
847    pub use hopper_runtime::crank::CrankMarker;
848    pub use hopper_runtime::dyn_cpi::DynCpi;
849
850    // `#[hopper::state]` and `#[hopper::pod]` emit bytemuck-backed
851    // proofs through this path so user code never needs a direct
852    // bytemuck dependency. Gated on the native backend because that's
853    // where the bytemuck re-export lives.
854    #[cfg(feature = "hopper-native-backend")]
855    pub use hopper_runtime::__hopper_native;
856
857    // Audit final-API Step 5 seal. Doc-hidden re-export of the
858    // sealed-trait module so macros can emit
859    // `unsafe impl ::hopper::__runtime::__sealed::HopperZeroCopySealed for Foo {}`
860    // without the user ever naming the private module.
861    pub use hopper_runtime::__sealed;
862
863    // Re-export `hopper_runtime::token` so `#[hopper::context]` can
864    // emit `::hopper::__runtime::token::require_token_mint(...)`
865    // without dragging the user into a direct `hopper_runtime`
866    // dependency. The helpers (require_token_mint / require_mint_*
867    // / require_token_authority) are read-only account-byte
868    // preconditions used to lower Anchor's `token::mint`,
869    // `mint::authority`, etc. constraints to a single inline check.
870    pub use hopper_runtime::token;
871}