switchboard_solana/attestation_program/instructions/
function_verify.rs

1use crate::cfg_client;
2use crate::prelude::*;
3
4#[derive(Accounts)]
5#[instruction(params: FunctionVerifyParams)] // rpc parameters hint
6pub struct FunctionVerify<'info> {
7    /// #[account(
8    ///     mut,
9    ///     seeds = [
10    ///         FUNCTION_SEED,
11    ///         function.load()?.creator_seed.as_ref(),
12    ///         &function.load()?.created_at_slot.to_le_bytes()
13    ///     ],
14    ///     bump = function.load()?.bump,
15    ///     has_one = attestation_queue @ SwitchboardError::InvalidQueue,
16    ///     has_one = escrow_token_wallet @ SwitchboardError::InvalidEscrow,
17    ///     has_one = escrow_wallet,
18    /// )]
19    /// pub function: AccountLoader<'info, FunctionAccountData>,
20    #[account(mut)]
21    pub function: AccountInfo<'info>, // FunctionAccountData
22
23    // #[account(signer)]
24    pub function_enclave_signer: Signer<'info>, // SystemProgram keypair
25
26    /// #[account(
27    ///     has_one = attestation_queue @ SwitchboardError::InvalidQueue,
28    ///     constraint = verifier.load()?.enclave.enclave_signer == verifier_signer.key() @ SwitchboardError::InvalidEnclaveSigner,
29    /// )]
30    /// pub verifier: AccountLoader<'info, VerifierAccountData>,
31    pub verifier: AccountInfo<'info>, // VerifierAccountData
32
33    // #[account(signer)]
34    pub verifier_signer: Signer<'info>,
35
36    /// #[account(
37    ///     seeds = [
38    ///         PERMISSION_SEED,
39    ///         attestation_queue.load()?.authority.as_ref(),
40    ///         attestation_queue.key().as_ref(),
41    ///         verifier.key().as_ref()
42    ///     ],
43    ///     bump = verifier_permission.load()?.bump,
44    /// )]
45    /// pub verifier_permission: AccountLoader<'info, AttestationPermissionAccountData>,
46    pub verifier_permission: AccountInfo<'info>, // AttestationPermissionAccountData
47
48    /// pub escrow_wallet: Box<Account<'info, SwitchboardWallet>>,
49    pub escrow_wallet: AccountInfo<'info>, // SwitchboardWallet
50
51    /// #[account(
52    ///     mut,
53    ///     constraint = escrow_token_wallet.is_native()
54    /// )]
55    /// pub escrow_token_wallet: Box<Account<'info, TokenAccount>>,
56    #[account(mut)]
57    pub escrow_token_wallet: AccountInfo<'info>, // TokenAccount
58
59    /// #[account(
60    ///     mut,
61    ///     constraint = receiver.is_native()
62    /// )]
63    /// pub receiver: Box<Account<'info, TokenAccount>>,
64    #[account(mut)]
65    pub receiver: AccountInfo<'info>, // TokenAccount
66
67    /// pub attestation_queue: AccountLoader<'info, AttestationQueueAccountData>,
68    pub attestation_queue: AccountInfo<'info>, // AttestationQueueAccountData
69
70    /// pub token_program: Program<'info, Token>,
71    #[account(address = anchor_spl::token::ID)]
72    pub token_program: AccountInfo<'info>,
73}
74
75#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
76pub struct FunctionVerifyParams {
77    pub observed_time: i64,
78    pub next_allowed_timestamp: i64,
79    pub error_code: u8,
80    pub mr_enclave: [u8; 32],
81}
82impl InstructionData for FunctionVerifyParams {}
83impl Discriminator for FunctionVerifyParams {
84    const DISCRIMINATOR: [u8; 8] = [210, 108, 154, 138, 198, 14, 53, 191];
85}
86impl Discriminator for FunctionVerify<'_> {
87    const DISCRIMINATOR: [u8; 8] = [210, 108, 154, 138, 198, 14, 53, 191];
88}
89
90cfg_client! {
91    pub struct FunctionVerifyAccounts {
92        /// The FunctionAccount pubkey to verify.
93        pub function: Pubkey,
94        /// The pubkey of the enclave generated keypair that will be set after verification.
95        /// This keypair must sign any subsequent instructions to prove the instructions
96        /// were generated within an enclave.
97        pub function_enclave_signer: Pubkey,
98        /// The Function's SwitchboardWallet pubkey used to reward verifiers.
99        pub function_escrow: Pubkey,
100
101        /// The VerifierAccount pubkey that is verifying the request.
102        pub verifier: Pubkey,
103        /// The VerifierAccount's enclave generated signer that must approve verifications.
104        pub verifier_enclave_signer: Pubkey,
105        /// The VerifierAccount's token wallet to receive a reward for verifying the request.
106        pub reward_receiver: Pubkey,
107
108        /// The AttestationQueueAccount that the request is being verified for.
109        pub attestation_queue: Pubkey,
110        /// The AttestationQueueAccount's authority. Used to derive the VerifierAccount's permission account.
111        pub queue_authority: Pubkey,
112    }
113    impl ToAccountMetas for FunctionVerifyAccounts {
114        fn to_account_metas(&self, _: Option<bool>) -> Vec<AccountMeta> {
115            vec![
116                AccountMeta::new(self.function, false),
117                AccountMeta::new_readonly(self.function_enclave_signer, true),
118                AccountMeta::new_readonly(self.verifier, false),
119                AccountMeta::new_readonly(self.verifier_enclave_signer, true),
120                AccountMeta::new_readonly(
121                    AttestationPermissionAccountData::get_pda(
122                        &self.queue_authority,
123                        &self.attestation_queue,
124                        &self.verifier
125                    ),
126                    false
127                ),
128                AccountMeta::new_readonly(self.function_escrow, false),
129                AccountMeta::new(crate::utils::find_associated_token_address(&self.function_escrow, &NativeMint::ID), false),
130                AccountMeta::new(self.reward_receiver, false),
131                AccountMeta::new_readonly(self.attestation_queue, false),
132                AccountMeta::new_readonly(anchor_spl::token::ID, false),
133            ]
134        }
135    }
136}
137
138impl<'info> FunctionVerify<'info> {
139    pub fn get_instruction(
140        &self,
141        program_id: Pubkey,
142        params: FunctionVerifyParams,
143    ) -> anchor_lang::Result<Instruction> {
144        let accounts = self.to_account_metas(None);
145
146        let mut data: Vec<u8> = FunctionVerify::discriminator().try_to_vec()?;
147        let mut param_vec: Vec<u8> = params.try_to_vec()?;
148        data.append(&mut param_vec);
149
150        let instruction = Instruction::new_with_bytes(program_id, &data, accounts);
151        Ok(instruction)
152    }
153
154    pub fn invoke(
155        &self,
156        program: AccountInfo<'info>,
157        observed_time: i64,
158        next_allowed_timestamp: i64,
159        error_code: u8,
160        mr_enclave: [u8; 32],
161    ) -> ProgramResult {
162        let cpi_params = FunctionVerifyParams {
163            observed_time,
164            next_allowed_timestamp,
165            error_code,
166            mr_enclave,
167        };
168        let instruction = self.get_instruction(*program.key, cpi_params)?;
169        let account_infos = self.to_account_infos();
170
171        invoke(&instruction, &account_infos[..])
172    }
173
174    pub fn invoke_signed(
175        &self,
176        program: AccountInfo<'info>,
177        observed_time: i64,
178        next_allowed_timestamp: i64,
179        error_code: u8,
180        mr_enclave: [u8; 32],
181        signer_seeds: &[&[&[u8]]],
182    ) -> ProgramResult {
183        let cpi_params = FunctionVerifyParams {
184            observed_time,
185            next_allowed_timestamp,
186            error_code,
187            mr_enclave,
188        };
189        let instruction = self.get_instruction(*program.key, cpi_params)?;
190        let account_infos = self.to_account_infos();
191
192        invoke_signed(&instruction, &account_infos[..], signer_seeds)
193    }
194
195    fn to_account_infos(&self) -> Vec<AccountInfo<'info>> {
196        let mut account_infos = Vec::new();
197        account_infos.extend(self.function.to_account_infos());
198        account_infos.extend(self.function_enclave_signer.to_account_infos());
199        account_infos.extend(self.verifier.to_account_infos());
200        account_infos.extend(self.verifier_signer.to_account_infos());
201        account_infos.extend(self.verifier_permission.to_account_infos());
202        account_infos.extend(self.escrow_wallet.to_account_infos());
203        account_infos.extend(self.escrow_token_wallet.to_account_infos());
204        account_infos.extend(self.receiver.to_account_infos());
205        account_infos.extend(self.attestation_queue.to_account_infos());
206        account_infos.extend(self.token_program.to_account_infos());
207        account_infos
208    }
209
210    #[allow(unused_variables)]
211    fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta> {
212        let mut account_metas = Vec::new();
213        account_metas.extend(self.function.to_account_metas(None));
214        account_metas.extend(self.function_enclave_signer.to_account_metas(Some(true)));
215        account_metas.extend(self.verifier.to_account_metas(None));
216        account_metas.extend(self.verifier_signer.to_account_metas(Some(true)));
217        account_metas.extend(self.verifier_permission.to_account_metas(None));
218        account_metas.extend(self.escrow_wallet.to_account_metas(None));
219        account_metas.extend(self.escrow_token_wallet.to_account_metas(None));
220        account_metas.extend(self.receiver.to_account_metas(None));
221        account_metas.extend(self.attestation_queue.to_account_metas(None));
222        account_metas.extend(self.token_program.to_account_metas(None));
223        account_metas
224    }
225
226    cfg_client! {
227        pub fn build_ix(
228            accounts: &FunctionVerifyAccounts,
229            params: &FunctionVerifyParams,
230        ) -> Result<Instruction, SbError> {
231
232            Ok(
233                crate::utils::build_ix(
234                    &SWITCHBOARD_ATTESTATION_PROGRAM_ID,
235                    accounts,
236                    params,
237                )
238            )
239        }
240    }
241}