spherenet_program_whitelist_interface/instructions.rs
1//! Instruction types
2
3use {
4 pinocchio::{
5 program_error::ProgramError,
6 pubkey::{Pubkey, PUBKEY_BYTES},
7 },
8 shank::ShankInstruction,
9};
10/// Instructions supported by the program whitelist program.
11#[repr(C)]
12#[derive(Clone, Debug, PartialEq, ShankInstruction)]
13pub enum ProgramWhitelistInstruction {
14 /// Proposes a new authority for the program whitelist. The current
15 /// `whitelist_authority` must sign this instruction. The proposed
16 /// `new_authority` must then sign an `AcceptAuthorityTransfer`
17 /// instruction to finalize the transfer.
18 ///
19 /// Accounts expected by this instruction:
20 ///
21 /// 0. `[writable]` The whitelist account
22 /// 1. `[signer]` The current whitelist authority
23 #[account(
24 0,
25 writable,
26 name = "whitelist_account",
27 desc = "The whitelist account"
28 )]
29 #[account(
30 1,
31 signer,
32 name = "whitelist_authority",
33 desc = "The whitelist authority"
34 )]
35 InitiateAuthorityTransfer { new_authority: Pubkey },
36
37 /// Accepts the pending authority transfer for the program whitelist. The
38 /// `pending_whitelist_authority` must sign this instruction to assume
39 /// authority over the whitelist.
40 ///
41 /// Accounts expected by this instruction:
42 ///
43 /// 0. `[writable]` The whitelist account
44 /// 1. `[signer]` The pending whitelist authority
45 #[account(
46 0,
47 writable,
48 name = "whitelist_account",
49 desc = "The whitelist account"
50 )]
51 #[account(
52 1,
53 signer,
54 name = "pending_whitelist_authority",
55 desc = "The pending whitelist authority"
56 )]
57 AcceptAuthorityTransfer,
58
59 /// Cancels a pending authority transfer for the program whitelist. The
60 /// current `whitelist_authority` must sign this instruction.
61 ///
62 /// Accounts expected by this instruction:
63 ///
64 /// 0. `[writable]` The whitelist account
65 /// 1. `[signer]` The current whitelist authority
66 #[account(
67 0,
68 writable,
69 name = "whitelist_account",
70 desc = "The whitelist account"
71 )]
72 #[account(
73 1,
74 signer,
75 name = "whitelist_authority",
76 desc = "The whitelist authority"
77 )]
78 CancelAuthorityTransfer {},
79
80 /// Requests a new entry on the program whitelist. Permissionless: the
81 /// `deploy_authority` being requested must sign, proving control of the
82 /// key. Creates a `Pending` entry that the `whitelist_authority` must later
83 /// approve (via `ApproveWhitelistEntry`) before it grants deploy access.
84 ///
85 /// Accounts expected by this instruction:
86 ///
87 /// 0. `[signer, writable]` Payer (funds the new entry account)
88 /// 1. `[signer]` The deploy authority being requested (proves key
89 /// control)
90 /// 2. `[]` The whitelist account (used for validation/derivation)
91 /// 3. `[writable]` The whitelist entry account to be created (Pending)
92 /// 4. `[]` System program
93 #[account(
94 0,
95 signer,
96 writable,
97 name = "payer",
98 desc = "Payer account (funds the new entry, must be a system account)"
99 )]
100 #[account(
101 1,
102 signer,
103 name = "deploy_authority",
104 desc = "The deploy authority being requested (signs to prove control)"
105 )]
106 #[account(
107 2,
108 name = "whitelist_account",
109 desc = "The whitelist account"
110 )]
111 #[account(
112 3,
113 writable,
114 name = "whitelist_entry_account",
115 desc = "The whitelist entry account"
116 )]
117 #[account(4, name = "system_program", desc = "System program")]
118 RequestWhitelistEntry,
119
120 /// Approves a pending whitelist entry, promoting it from `Pending` to
121 /// `Approved` (active — the deploy gate then passes for that authority).
122 /// The `whitelist_authority` must sign this instruction.
123 ///
124 /// Accounts expected by this instruction:
125 ///
126 /// 0. `[signer]` Payer
127 /// 1. `[signer]` The whitelist authority
128 /// 2. `[]` The whitelist account (used for validation)
129 /// 3. `[writable]` The whitelist entry account to approve
130 #[account(
131 0,
132 signer,
133 name = "payer",
134 desc = "Payer account"
135 )]
136 #[account(
137 1,
138 signer,
139 name = "whitelist_authority",
140 desc = "The whitelist authority"
141 )]
142 #[account(
143 2,
144 name = "whitelist_account",
145 desc = "The whitelist account"
146 )]
147 #[account(
148 3,
149 writable,
150 name = "whitelist_entry_account",
151 desc = "The whitelist entry account to approve"
152 )]
153 ApproveWhitelistEntry { deploy_authority: Pubkey },
154
155 /// Rejects a pending whitelist entry, closing it and reclaiming its rent
156 /// lamports to the payer. Only a `Pending` entry may be rejected (an active
157 /// `Approved` entry is removed via `RemoveWhitelistEntry`). The
158 /// `whitelist_authority` must sign this instruction.
159 ///
160 /// Accounts expected by this instruction:
161 ///
162 /// 0. `[signer, writable]` Payer (receives reclaimed rent)
163 /// 1. `[signer]` The whitelist authority
164 /// 2. `[]` The whitelist account (used for validation)
165 /// 3. `[writable]` The whitelist entry account to reject
166 #[account(
167 0,
168 signer,
169 writable,
170 name = "payer",
171 desc = "Payer account (receives reclaimed rent)"
172 )]
173 #[account(
174 1,
175 signer,
176 name = "whitelist_authority",
177 desc = "The whitelist authority"
178 )]
179 #[account(
180 2,
181 name = "whitelist_account",
182 desc = "The whitelist account"
183 )]
184 #[account(
185 3,
186 writable,
187 name = "whitelist_entry_account",
188 desc = "The whitelist entry account to reject"
189 )]
190 RejectWhitelistEntry { deploy_authority: Pubkey },
191
192 /// Closes a whitelist entry account, reclaiming its rent lamports to the
193 /// payer. The `whitelist_authority` must sign this instruction.
194 ///
195 /// Accounts expected by this instruction:
196 ///
197 /// 0. `[signer, writable]` Payer (receives reclaimed rent)
198 /// 1. `[signer]` The whitelist authority
199 /// 2. `[]` The whitelist account (used for validation)
200 /// 3. `[writable]` The whitelist entry account to close
201 #[account(
202 0,
203 signer,
204 writable,
205 name = "payer",
206 desc = "Payer account (receives reclaimed rent)"
207 )]
208 #[account(
209 1,
210 signer,
211 name = "whitelist_authority",
212 desc = "The whitelist authority"
213 )]
214 #[account(
215 2,
216 name = "whitelist_account",
217 desc = "The whitelist account"
218 )]
219 #[account(
220 3,
221 writable,
222 name = "whitelist_entry_account",
223 desc = "The whitelist entry account to close"
224 )]
225 RemoveWhitelistEntry { deploy_authority: Pubkey },
226}
227
228impl ProgramWhitelistInstruction {
229 /// Instruction discriminant tags — the single source of truth for the
230 /// leading byte of each instruction's data. Both `unpack` (below) and the
231 /// `onchain` CPI builders reference these, so a renumber happens in exactly
232 /// one place. Values MUST match the enum's positional order: the shank IDL
233 /// and the generated clients derive their discriminants positionally.
234 pub const INITIATE_AUTHORITY_TRANSFER_TAG: u8 = 0;
235 pub const ACCEPT_AUTHORITY_TRANSFER_TAG: u8 = 1;
236 pub const CANCEL_AUTHORITY_TRANSFER_TAG: u8 = 2;
237 pub const REQUEST_WHITELIST_ENTRY_TAG: u8 = 3;
238 pub const APPROVE_WHITELIST_ENTRY_TAG: u8 = 4;
239 pub const REJECT_WHITELIST_ENTRY_TAG: u8 = 5;
240 pub const REMOVE_WHITELIST_ENTRY_TAG: u8 = 6;
241
242 /// Unpack a program whitelist instruction from a byte slice.
243 pub fn unpack(input: &[u8]) -> Result<Self, ProgramError> {
244 let (&tag, rest) = input
245 .split_first()
246 .ok_or(ProgramError::InvalidInstructionData)?;
247 match tag {
248 Self::INITIATE_AUTHORITY_TRANSFER_TAG if rest.len() == PUBKEY_BYTES => {
249 let new_authority = Pubkey::try_from(rest).unwrap();
250 Ok(Self::InitiateAuthorityTransfer { new_authority })
251 }
252 Self::ACCEPT_AUTHORITY_TRANSFER_TAG if rest.is_empty() => {
253 Ok(Self::AcceptAuthorityTransfer)
254 }
255 Self::CANCEL_AUTHORITY_TRANSFER_TAG if rest.is_empty() => {
256 Ok(Self::CancelAuthorityTransfer {})
257 }
258 Self::REQUEST_WHITELIST_ENTRY_TAG if rest.is_empty() => {
259 Ok(Self::RequestWhitelistEntry)
260 }
261 Self::APPROVE_WHITELIST_ENTRY_TAG if rest.len() == PUBKEY_BYTES => {
262 let deploy_authority = Pubkey::try_from(rest).unwrap();
263 Ok(Self::ApproveWhitelistEntry { deploy_authority })
264 }
265 Self::REJECT_WHITELIST_ENTRY_TAG if rest.len() == PUBKEY_BYTES => {
266 let deploy_authority = Pubkey::try_from(rest).unwrap();
267 Ok(Self::RejectWhitelistEntry { deploy_authority })
268 }
269 Self::REMOVE_WHITELIST_ENTRY_TAG if rest.len() == PUBKEY_BYTES => {
270 let deploy_authority = Pubkey::try_from(rest).unwrap();
271 Ok(Self::RemoveWhitelistEntry { deploy_authority })
272 }
273 _ => Err(ProgramError::InvalidInstructionData),
274 }
275 }
276}