Skip to main content

hopper_runtime/
proof.rs

1//! Proof-carrying account markers.
2//!
3//! This is the lightweight capability layer over `AccountView` checks. Each
4//! method consumes a proof and returns the same account with an extra marker in
5//! the type, so downstream helpers can require `OwnerChecked`, `SignerChecked`,
6//! `LayoutChecked<T>`, or any tuple composition of those markers.
7
8use core::marker::PhantomData;
9
10use crate::{AccountView, Address, LayoutContract, ProgramError};
11
12#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
13pub struct Unchecked;
14#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
15pub struct OwnerChecked;
16#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
17pub struct LayoutChecked<T>(PhantomData<T>);
18#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
19pub struct SignerChecked;
20#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
21pub struct WritableChecked;
22#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
23pub struct ExecutableChecked;
24#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
25pub struct TokenExtensionsChecked;
26#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
27pub struct SeedsChecked;
28#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
29pub struct HasOneChecked;
30
31#[derive(Clone, Copy)]
32pub struct AccountProof<'a, P = Unchecked> {
33    account: &'a AccountView,
34    _proof: PhantomData<P>,
35}
36
37impl<'a> AccountProof<'a, Unchecked> {
38    #[inline(always)]
39    pub const fn new(account: &'a AccountView) -> Self {
40        Self {
41            account,
42            _proof: PhantomData,
43        }
44    }
45}
46
47impl<'a, P> AccountProof<'a, P> {
48    #[inline(always)]
49    pub const fn account(&self) -> &'a AccountView {
50        self.account
51    }
52
53    #[inline(always)]
54    pub fn check_owner(
55        self,
56        expected: &Address,
57    ) -> Result<AccountProof<'a, (P, OwnerChecked)>, ProgramError> {
58        self.account.check_owned_by(expected)?;
59        Ok(AccountProof::<'a, (P, OwnerChecked)> {
60            account: self.account,
61            _proof: PhantomData,
62        })
63    }
64
65    #[inline(always)]
66    pub fn check_layout<T: LayoutContract>(
67        self,
68    ) -> Result<AccountProof<'a, (P, LayoutChecked<T>)>, ProgramError> {
69        self.account.check_layout::<T>()?;
70        Ok(AccountProof::<'a, (P, LayoutChecked<T>)> {
71            account: self.account,
72            _proof: PhantomData,
73        })
74    }
75
76    #[inline(always)]
77    pub fn check_signer(self) -> Result<AccountProof<'a, (P, SignerChecked)>, ProgramError> {
78        self.account.check_signer()?;
79        Ok(AccountProof::<'a, (P, SignerChecked)> {
80            account: self.account,
81            _proof: PhantomData,
82        })
83    }
84
85    #[inline(always)]
86    pub fn check_writable(self) -> Result<AccountProof<'a, (P, WritableChecked)>, ProgramError> {
87        self.account.check_writable()?;
88        Ok(AccountProof::<'a, (P, WritableChecked)> {
89            account: self.account,
90            _proof: PhantomData,
91        })
92    }
93
94    #[inline(always)]
95    pub fn check_executable(
96        self,
97    ) -> Result<AccountProof<'a, (P, ExecutableChecked)>, ProgramError> {
98        self.account.check_executable()?;
99        Ok(AccountProof::<'a, (P, ExecutableChecked)> {
100            account: self.account,
101            _proof: PhantomData,
102        })
103    }
104
105    #[inline(always)]
106    pub const fn assume_token_extensions_checked(
107        self,
108    ) -> AccountProof<'a, (P, TokenExtensionsChecked)> {
109        AccountProof::<'a, (P, TokenExtensionsChecked)> {
110            account: self.account,
111            _proof: PhantomData,
112        }
113    }
114}