Skip to main content

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}