Skip to main content

hopper_runtime/compat/
native.rs

1use crate::account::AccountView;
2use crate::address::Address;
3use crate::error::ProgramError;
4use crate::ProgramResult;
5
6pub type BackendAccountView = hopper_native::AccountView;
7pub type BackendAddress = hopper_native::Address;
8pub type BackendProgramResult = hopper_native::ProgramResult;
9pub type BackendRef<'a, T> = hopper_native::borrow::Ref<'a, T>;
10pub type BackendRefMut<'a, T> = hopper_native::borrow::RefMut<'a, T>;
11pub const BACKEND_MAX_TX_ACCOUNTS: usize = hopper_native::MAX_TX_ACCOUNTS;
12pub const BACKEND_SUCCESS: u64 = hopper_native::SUCCESS;
13
14#[inline(always)]
15pub unsafe fn wrap_account_slice(accounts: &[BackendAccountView]) -> &[AccountView] {
16    unsafe { core::slice::from_raw_parts(accounts.as_ptr() as *const AccountView, accounts.len()) }
17}
18
19#[inline(always)]
20pub fn account_address(view: &BackendAccountView) -> &Address {
21    unsafe { &*(view.address() as *const BackendAddress as *const Address) }
22}
23
24#[inline(always)]
25pub unsafe fn account_owner(view: &BackendAccountView) -> &Address {
26    unsafe { &*(view.owner() as *const BackendAddress as *const Address) }
27}
28
29#[inline(always)]
30pub fn read_owner(view: &BackendAccountView) -> Address {
31    Address::from(view.read_owner())
32}
33
34#[inline(always)]
35pub fn as_backend_address(address: &Address) -> &BackendAddress {
36    unsafe { &*(address as *const Address as *const BackendAddress) }
37}
38
39#[inline(always)]
40pub fn owned_by(view: &BackendAccountView, program: &Address) -> bool {
41    view.owned_by(as_backend_address(program))
42}
43
44#[inline(always)]
45pub fn disc(view: &BackendAccountView) -> u8 {
46    view.disc()
47}
48
49#[inline(always)]
50pub fn version(view: &BackendAccountView) -> u8 {
51    view.version()
52}
53
54#[inline(always)]
55pub fn layout_id(view: &BackendAccountView) -> Option<&[u8; 8]> {
56    view.layout_id()
57}
58
59#[inline(always)]
60pub unsafe fn assign(view: &BackendAccountView, new_owner: &Address) {
61    unsafe { view.assign(as_backend_address(new_owner)); }
62}
63
64#[inline(always)]
65pub fn close(view: &BackendAccountView) -> ProgramResult {
66    view.close().map_err(ProgramError::from)
67}
68
69#[inline(always)]
70pub fn zero_data(view: &BackendAccountView) -> ProgramResult {
71    let mut data = view.try_borrow_mut().map_err(ProgramError::from)?;
72    let mut i = 0;
73    while i < data.len() {
74        data[i] = 0;
75        i += 1;
76    }
77    Ok(())
78}
79
80#[cfg(target_os = "solana")]
81#[inline(always)]
82pub fn find_program_address(seeds: &[&[u8]], program_id: &Address) -> (Address, u8) {
83    let (address, bump) = hopper_native::pda::find_program_address(seeds, as_backend_address(program_id));
84    (Address::from(address), bump)
85}
86
87#[inline(always)]
88pub fn create_program_address(seeds: &[&[u8]], program_id: &Address) -> Result<Address, ProgramError> {
89    #[cfg(target_os = "solana")]
90    {
91        hopper_native::pda::create_program_address(seeds, as_backend_address(program_id))
92            .map(Address::from)
93            .map_err(|_| ProgramError::InvalidSeeds)
94    }
95    #[cfg(not(target_os = "solana"))]
96    {
97        let _ = (seeds, program_id);
98        Err(ProgramError::InvalidSeeds)
99    }
100}
101
102#[inline(always)]
103pub unsafe fn process_entrypoint<const MAX: usize>(
104    input: *mut u8,
105    process_instruction: fn(&BackendAddress, &[BackendAccountView], &[u8]) -> BackendProgramResult,
106) -> u64 {
107    unsafe { hopper_native::entrypoint::process_entrypoint::<MAX>(input, process_instruction) }
108}
109
110#[inline(always)]
111pub fn bridge_to_runtime(
112    program_id: &BackendAddress,
113    accounts: &[BackendAccountView],
114    data: &[u8],
115    process_instruction: fn(&Address, &[AccountView], &[u8]) -> ProgramResult,
116) -> BackendProgramResult {
117    let hopper_id = unsafe { &*(program_id as *const BackendAddress as *const Address) };
118    let hopper_accounts = unsafe { wrap_account_slice(accounts) };
119    match process_instruction(hopper_id, hopper_accounts, data) {
120        Ok(()) => Ok(()),
121        Err(error) => Err(error.into()),
122    }
123}
124
125#[inline(always)]
126pub fn set_return_data(data: &[u8]) {
127    #[cfg(target_os = "solana")]
128    unsafe {
129        hopper_native::syscalls::sol_set_return_data(data.as_ptr(), data.len() as u64);
130    }
131    #[cfg(not(target_os = "solana"))]
132    {
133        let _ = data;
134    }
135}
136
137impl From<BackendAddress> for Address {
138    #[inline(always)]
139    fn from(address: BackendAddress) -> Self {
140        Self(address.to_bytes())
141    }
142}
143
144impl From<Address> for BackendAddress {
145    #[inline(always)]
146    fn from(address: Address) -> Self {
147        BackendAddress::new_from_array(address.to_bytes())
148    }
149}