hopper_core/accounts/entry.rs
1//! Typed instruction entry model.
2//!
3//! Provides `HopperIx` trait for instruction definition and `hopper_entry()`
4//! for clean instruction dispatch. Bridges the Account DSL to Hopper's
5//! existing dispatch system.
6
7use hopper_runtime::error::ProgramError;
8use hopper_runtime::{AccountView, Address};
9
10use super::context::{HopperAccounts, HopperCtx};
11
12/// Trait defining a Hopper instruction.
13///
14/// Combines argument parsing with account construction into a single
15/// instruction definition. Used with `hopper_entry()` for typed dispatch.
16pub trait HopperIx<'a>: Sized {
17 /// The account struct for this instruction.
18 type Accounts: HopperAccounts<'a>;
19 /// The parsed argument type.
20 type Args;
21
22 /// Parse instruction arguments from raw data (after dispatch tag).
23 fn parse_args(data: &'a [u8]) -> Result<Self::Args, ProgramError>;
24}
25
26/// Typed instruction entry point.
27///
28/// Parses arguments, constructs the validated context, and invokes the handler.
29/// One-line replacement for manual dispatch + parse + validate + execute.
30///
31/// ```ignore
32/// hopper_entry::<DepositIx, _>(program_id, accounts, data, |ctx, args| {
33/// deposit(ctx, args.amount)
34/// })
35/// ```
36#[inline]
37pub fn hopper_entry<'a, I, F>(
38 program_id: &'a Address,
39 accounts: &'a [AccountView],
40 instruction_data: &'a [u8],
41 handler: F,
42) -> Result<(), ProgramError>
43where
44 I: HopperIx<'a>,
45 F: FnOnce(HopperCtx<'a, I::Accounts>, I::Args) -> Result<(), ProgramError>,
46{
47 let args = I::parse_args(instruction_data)?;
48 let (accts, bumps) = I::Accounts::try_from_accounts(program_id, accounts, instruction_data)?;
49 let consumed = I::Accounts::ACCOUNT_COUNT;
50 let remaining = if consumed < accounts.len() {
51 &accounts[consumed..]
52 } else {
53 &[]
54 };
55 let ctx = HopperCtx::new(accts, bumps, program_id, instruction_data, remaining);
56 handler(ctx, args)
57}