pinocchio_token/instructions/
revoke.rs1use {
2 crate::{
3 instructions::{
4 account_borrow_failed_error, invalid_argument_error, CpiWriter, MAX_MULTISIG_SIGNERS,
5 },
6 UNINIT_BYTE, UNINIT_CPI_ACCOUNT, UNINIT_INSTRUCTION_ACCOUNT,
7 },
8 core::{mem::MaybeUninit, slice::from_raw_parts},
9 solana_account_view::AccountView,
10 solana_instruction_view::{
11 cpi::{invoke_signed_unchecked, CpiAccount, Signer},
12 InstructionAccount, InstructionView,
13 },
14 solana_program_error::{ProgramError, ProgramResult},
15};
16
17pub struct Revoke<'account, 'multisig, MultisigSigner: AsRef<AccountView>> {
30 pub source: &'account AccountView,
32
33 pub authority: &'account AccountView,
35
36 pub multisig_signers: &'multisig [MultisigSigner],
38}
39
40impl<'account> Revoke<'account, '_, &'account AccountView> {
41 pub const DISCRIMINATOR: u8 = 5;
43
44 pub const MAX_ACCOUNTS_LEN: usize = 2 + MAX_MULTISIG_SIGNERS;
50
51 pub const DATA_LEN: usize = 1;
54
55 #[inline(always)]
57 pub fn new(source: &'account AccountView, authority: &'account AccountView) -> Self {
58 Self::with_multisig_signers(source, authority, &[])
59 }
60}
61
62impl<'account, 'multisig, MultisigSigner: AsRef<AccountView>>
63 Revoke<'account, 'multisig, MultisigSigner>
64{
65 #[inline(always)]
68 pub fn with_multisig_signers(
69 source: &'account AccountView,
70 authority: &'account AccountView,
71 multisig_signers: &'multisig [MultisigSigner],
72 ) -> Self {
73 Self {
74 source,
75 authority,
76 multisig_signers,
77 }
78 }
79
80 #[inline(always)]
81 pub fn invoke(&self) -> ProgramResult {
82 self.invoke_signed(&[])
83 }
84
85 #[inline(always)]
86 pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
87 if self.multisig_signers.len() > MAX_MULTISIG_SIGNERS {
88 Err(ProgramError::InvalidArgument)?;
89 }
90
91 let mut instruction_accounts = [UNINIT_INSTRUCTION_ACCOUNT; Revoke::MAX_ACCOUNTS_LEN];
92 let written_instruction_accounts =
93 self.write_instruction_accounts(&mut instruction_accounts)?;
94
95 let mut accounts = [UNINIT_CPI_ACCOUNT; Revoke::MAX_ACCOUNTS_LEN];
96 let written_accounts = self.write_accounts(&mut accounts)?;
97
98 let mut instruction_data = [UNINIT_BYTE; Revoke::DATA_LEN];
99 let written_instruction_data = self.write_instruction_data(&mut instruction_data)?;
100
101 unsafe {
102 invoke_signed_unchecked(
103 &InstructionView {
104 program_id: &crate::ID,
105 accounts: from_raw_parts(
106 instruction_accounts.as_ptr() as _,
107 written_instruction_accounts,
108 ),
109 data: from_raw_parts(instruction_data.as_ptr() as _, written_instruction_data),
110 },
111 from_raw_parts(accounts.as_ptr() as _, written_accounts),
112 signers,
113 );
114 }
115
116 Ok(())
117 }
118}
119
120impl<MultisigSigner: AsRef<AccountView>> CpiWriter for Revoke<'_, '_, MultisigSigner> {
121 #[inline(always)]
122 fn write_accounts<'cpi>(
123 &self,
124 accounts: &mut [MaybeUninit<CpiAccount<'cpi>>],
125 ) -> Result<usize, ProgramError>
126 where
127 Self: 'cpi,
128 {
129 write_accounts(self.source, self.authority, self.multisig_signers, accounts)
130 }
131
132 #[inline(always)]
133 fn write_instruction_accounts<'cpi>(
134 &self,
135 accounts: &mut [MaybeUninit<InstructionAccount<'cpi>>],
136 ) -> Result<usize, ProgramError>
137 where
138 Self: 'cpi,
139 {
140 write_instruction_accounts(self.source, self.authority, self.multisig_signers, accounts)
141 }
142
143 #[inline(always)]
144 fn write_instruction_data(&self, data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
145 write_instruction_data(data)
146 }
147}
148
149impl<MultisigSigner: AsRef<AccountView>> super::IntoBatch for Revoke<'_, '_, MultisigSigner> {
150 #[inline(always)]
151 fn into_batch<'account, 'state>(
152 self,
153 batch: &mut super::Batch<'account, 'state>,
154 ) -> ProgramResult
155 where
156 Self: 'account + 'state,
157 {
158 batch.push(
159 |accounts| write_accounts(self.source, self.authority, self.multisig_signers, accounts),
160 |accounts| {
161 write_instruction_accounts(
162 self.source,
163 self.authority,
164 self.multisig_signers,
165 accounts,
166 )
167 },
168 write_instruction_data,
169 )
170 }
171}
172
173#[inline(always)]
174fn write_accounts<'account, 'multisig, 'out, MultisigSigner: AsRef<AccountView>>(
175 source: &'account AccountView,
176 authority: &'account AccountView,
177 multisig_signers: &'multisig [MultisigSigner],
178 accounts: &mut [MaybeUninit<CpiAccount<'out>>],
179) -> Result<usize, ProgramError>
180where
181 'account: 'out,
182 'multisig: 'out,
183{
184 let expected_accounts = 2 + multisig_signers.len();
185
186 if expected_accounts > accounts.len() {
187 return Err(invalid_argument_error());
188 }
189
190 if source.is_borrowed() {
191 return Err(account_borrow_failed_error());
192 }
193
194 CpiAccount::init_from_account_view(source, &mut accounts[0]);
195
196 CpiAccount::init_from_account_view(authority, &mut accounts[1]);
197
198 for (account, signer) in accounts[2..expected_accounts]
199 .iter_mut()
200 .zip(multisig_signers.iter())
201 {
202 CpiAccount::init_from_account_view(signer.as_ref(), account);
203 }
204
205 Ok(expected_accounts)
206}
207
208#[inline(always)]
209fn write_instruction_accounts<'account, 'multisig, 'out, MultisigSigner: AsRef<AccountView>>(
210 source: &'account AccountView,
211 authority: &'account AccountView,
212 multisig_signers: &'multisig [MultisigSigner],
213 accounts: &mut [MaybeUninit<InstructionAccount<'out>>],
214) -> Result<usize, ProgramError>
215where
216 'account: 'out,
217 'multisig: 'out,
218{
219 let expected_accounts = 2 + multisig_signers.len();
220
221 if expected_accounts > accounts.len() {
222 return Err(invalid_argument_error());
223 }
224
225 accounts[0].write(InstructionAccount::writable(source.address()));
226
227 accounts[1].write(InstructionAccount::new(
228 authority.address(),
229 false,
230 multisig_signers.is_empty(),
231 ));
232
233 for (account, signer) in accounts[2..expected_accounts]
234 .iter_mut()
235 .zip(multisig_signers.iter())
236 {
237 account.write(InstructionAccount::readonly_signer(
238 signer.as_ref().address(),
239 ));
240 }
241
242 Ok(expected_accounts)
243}
244
245#[inline(always)]
246fn write_instruction_data(data: &mut [MaybeUninit<u8>]) -> Result<usize, ProgramError> {
247 if data.len() < Revoke::DATA_LEN {
248 return Err(invalid_argument_error());
249 }
250
251 data[0].write(Revoke::DISCRIMINATOR);
252
253 Ok(Revoke::DATA_LEN)
254}