hayabusa_cpi/
lib.rs

1// Copyright (c) 2025, Arcane Labs <dev@arcane.fi>
2// SPDX-License-Identifier: Apache-2.0
3
4#![no_std]
5
6use hayabusa_errors::Result;
7use hayabusa_utility::fail_with_ctx;
8use pinocchio::{
9    account_info::AccountInfo, hint::unlikely, instruction::Signer, program_error::ProgramError, pubkey::Pubkey
10};
11
12pub trait CheckProgramId {
13    const ID: Pubkey;
14
15    #[inline(always)]
16    fn check_program_id(id: &Pubkey) -> Result<()> {
17        if unlikely(id != &Self::ID) {
18            fail_with_ctx!(
19                "HAYABUSA_CPI_INCORRECT_PROGRAM_ID",
20                ProgramError::IncorrectProgramId,
21                id,
22                &Self::ID,
23            );
24        }
25
26        Ok(())
27    }
28}
29
30pub struct CpiCtx<'a, 'b, 'c, 'd, T: CheckProgramId> {
31    pub program_info: &'a AccountInfo,
32    pub accounts: T,
33    pub signers: Option<&'b [Signer<'c, 'd>]>,
34}
35
36impl<'a, 'b, 'c, 'd, T: CheckProgramId> CpiCtx<'a, 'b, 'c, 'd, T> {
37    #[inline(always)]
38    pub fn try_new(
39        program_info: &'a AccountInfo,
40        accounts: T,
41        signers: Option<&'b [Signer<'c, 'd>]>,
42    ) -> Result<Self> {
43        T::check_program_id(program_info.key())?;
44
45        Ok(Self {
46            program_info,
47            accounts,
48            signers,
49        })
50    }
51
52    #[inline(always)]
53    pub fn try_new_without_signer(
54        program_info: &'a AccountInfo,
55        accounts: T,
56    ) -> Result<Self> {
57        T::check_program_id(program_info.key())?;
58
59        Ok(Self {
60            program_info,
61            accounts,
62            signers: None,
63        })
64    }
65
66    #[inline(always)]
67    pub fn try_new_with_signer(
68        program_info: &'a AccountInfo,
69        accounts: T,
70        signers: &'b [Signer<'c, 'd>],
71    ) -> Result<Self> {
72        T::check_program_id(program_info.key())?;
73
74        Ok(Self {
75            program_info,
76            accounts,
77            signers: Some(signers),
78        })
79    }
80}
81
82impl<T: CheckProgramId> core::ops::Deref for CpiCtx<'_, '_, '_, '_, T> {
83    type Target = T;
84
85    #[inline(always)]
86    fn deref(&self) -> &Self::Target {
87        &self.accounts
88    }
89}