spam/
instruction.rs

1use bytemuck::{Pod, Zeroable};
2use num_enum::TryFromPrimitive;
3use shank::ShankInstruction;
4use solana_program::{
5    instruction::{AccountMeta, Instruction},
6    pubkey::Pubkey,
7    system_program, sysvar,
8};
9
10use crate::{
11    impl_instruction_from_bytes, impl_to_bytes, state::Hash, BUS, /*METADATA,*/ MINT, MINT_ADDRESS,
12    MINT_NOISE, PROOF, TREASURY, TREASURY_ADDRESS,
13};
14
15#[repr(u8)]
16#[derive(Clone, Copy, Debug, Eq, PartialEq, ShankInstruction, TryFromPrimitive)]
17#[rustfmt::skip]
18pub enum OreInstruction {
19    #[account(0, name = "spam_program", desc = "Spam program")]
20    #[account(1, name = "signer", desc = "Signer", signer)]
21    #[account(2, name = "bus_0", desc = "Spam bus account 0", writable)]
22    #[account(3, name = "bus_1", desc = "Spam bus account 1", writable)]
23    #[account(4, name = "bus_2", desc = "Spam bus account 2", writable)]
24    #[account(5, name = "bus_3", desc = "Spam bus account 3", writable)]
25    #[account(6, name = "bus_4", desc = "Spam bus account 4", writable)]
26    #[account(7, name = "bus_5", desc = "Spam bus account 5", writable)]
27    #[account(8, name = "bus_6", desc = "Spam bus account 6", writable)]
28    #[account(9, name = "bus_7", desc = "Spam bus account 7", writable)]
29    #[account(10, name = "mint", desc = "Spam token mint account", writable)]
30    #[account(11, name = "treasury", desc = "Spam treasury account", writable)]
31    #[account(12, name = "treasury_tokens", desc = "Spam treasury token account", writable)]
32    #[account(13, name = "token_program", desc = "SPL token program")]
33    Reset = 0,
34
35    #[account(0, name = "spam_program", desc = "Spam program")]
36    #[account(1, name = "signer", desc = "Signer", signer)]
37    #[account(2, name = "proof", desc = "Spam proof account", writable)]
38    #[account(3, name = "system_program", desc = "Solana system program")]
39    Register = 1,
40
41    #[account(0, name = "spam_program", desc = "Spam program")]
42    #[account(1, name = "signer", desc = "Signer", signer)]
43    #[account(2, name = "bus", desc = "Spam bus account", writable)]
44    #[account(3, name = "proof", desc = "Spam proof account", writable)]
45    #[account(4, name = "treasury", desc = "Spam treasury account")]
46    #[account(5, name = "slot_hashes", desc = "Solana slot hashes sysvar")]
47    Mine = 2,
48
49    #[account(0, name = "spam_program", desc = "Spam program")]
50    #[account(1, name = "signer", desc = "Signer", signer)]
51    #[account(2, name = "beneficiary", desc = "Beneficiary token account", writable)]
52    #[account(3, name = "proof", desc = "Spam proof account", writable)]
53    #[account(4, name = "treasury", desc = "Spam treasury account", writable)]
54    #[account(5, name = "treasury_tokens", desc = "Spam treasury token account", writable)]
55    #[account(6, name = "token_program", desc = "SPL token program")]
56    Claim = 3,
57
58    #[account(0, name = "spam_program", desc = "Spam program")]
59    #[account(1, name = "signer", desc = "Admin signer", signer)]
60    #[account(2, name = "bus_0", desc = "Spam bus account 0", writable)]
61    #[account(3, name = "bus_1", desc = "Spam bus account 1", writable)]
62    #[account(4, name = "bus_2", desc = "Spam bus account 2", writable)]
63    #[account(5, name = "bus_3", desc = "Spam bus account 3", writable)]
64    #[account(6, name = "bus_4", desc = "Spam bus account 4", writable)]
65    #[account(7, name = "bus_5", desc = "Spam bus account 5", writable)]
66    #[account(8, name = "bus_6", desc = "Spam bus account 6", writable)]
67    #[account(9, name = "bus_7", desc = "Spam bus account 7", writable)]
68    #[account(10, name = "mint", desc = "Spam mint account", writable)]
69    #[account(11, name = "treasury", desc = "Spam treasury account", writable)]
70    #[account(12, name = "treasury_tokens", desc = "Spam treasury token account", writable)]
71    #[account(13, name = "system_program", desc = "Solana system program")]
72    #[account(14, name = "token_program", desc = "SPL token program")]
73    #[account(15, name = "associated_token_program", desc = "SPL associated token program")]
74    #[account(16, name = "rent", desc = "Solana rent sysvar")]
75    Initialize = 100,
76
77    #[account(0, name = "spam_program", desc = "Spam program")]
78    #[account(1, name = "signer", desc = "Admin signer", signer)]
79    #[account(2, name = "treasury", desc = "Spam treasury account")]
80    UpdateAdmin = 101,
81
82    #[account(0, name = "spam_program", desc = "Spam program")]
83    #[account(1, name = "signer", desc = "Admin signer", signer)]
84    #[account(2, name = "treasury", desc = "Spam treasury account")]
85    UpdateDifficulty = 102,
86}
87
88impl OreInstruction {
89    pub fn to_vec(&self) -> Vec<u8> {
90        vec![*self as u8]
91    }
92}
93
94#[repr(C)]
95#[derive(Clone, Copy, Debug, Pod, Zeroable)]
96pub struct InitializeArgs {
97    pub bus_0_bump: u8,
98    pub bus_1_bump: u8,
99    pub bus_2_bump: u8,
100    pub bus_3_bump: u8,
101    pub bus_4_bump: u8,
102    pub bus_5_bump: u8,
103    pub bus_6_bump: u8,
104    pub bus_7_bump: u8,
105    // pub metadata_bump: u8,
106    pub mint_bump: u8,
107    pub treasury_bump: u8,
108}
109
110#[repr(C)]
111#[derive(Clone, Copy, Debug, Pod, Zeroable)]
112pub struct RegisterArgs {
113    pub bump: u8,
114}
115
116#[repr(C)]
117#[derive(Clone, Copy, Debug, Pod, Zeroable)]
118pub struct MineArgs {
119    pub hash: Hash,
120    pub nonce: [u8; 8],
121}
122
123#[repr(C)]
124#[derive(Clone, Copy, Debug, Pod, Zeroable)]
125pub struct ClaimArgs {
126    pub amount: [u8; 8],
127}
128
129#[repr(C)]
130#[derive(Clone, Copy, Debug, Pod, Zeroable)]
131pub struct UpdateAdminArgs {
132    pub new_admin: Pubkey,
133}
134
135#[repr(C)]
136#[derive(Clone, Copy, Debug, Pod, Zeroable)]
137pub struct UpdateDifficultyArgs {
138    pub new_difficulty: Hash,
139}
140
141impl_to_bytes!(InitializeArgs);
142impl_to_bytes!(RegisterArgs);
143impl_to_bytes!(MineArgs);
144impl_to_bytes!(ClaimArgs);
145impl_to_bytes!(UpdateAdminArgs);
146impl_to_bytes!(UpdateDifficultyArgs);
147
148impl_instruction_from_bytes!(InitializeArgs);
149impl_instruction_from_bytes!(RegisterArgs);
150impl_instruction_from_bytes!(MineArgs);
151impl_instruction_from_bytes!(ClaimArgs);
152impl_instruction_from_bytes!(UpdateAdminArgs);
153impl_instruction_from_bytes!(UpdateDifficultyArgs);
154
155/// Builds a reset instruction.
156pub fn reset(signer: Pubkey) -> Instruction {
157    let bus_0 = Pubkey::find_program_address(&[BUS, &[0]], &crate::id()).0;
158    let bus_1 = Pubkey::find_program_address(&[BUS, &[1]], &crate::id()).0;
159    let bus_2 = Pubkey::find_program_address(&[BUS, &[2]], &crate::id()).0;
160    let bus_3 = Pubkey::find_program_address(&[BUS, &[3]], &crate::id()).0;
161    let bus_4 = Pubkey::find_program_address(&[BUS, &[4]], &crate::id()).0;
162    let bus_5 = Pubkey::find_program_address(&[BUS, &[5]], &crate::id()).0;
163    let bus_6 = Pubkey::find_program_address(&[BUS, &[6]], &crate::id()).0;
164    let bus_7 = Pubkey::find_program_address(&[BUS, &[7]], &crate::id()).0;
165    let treasury_tokens = spl_associated_token_account::get_associated_token_address(
166        &TREASURY_ADDRESS,
167        &MINT_ADDRESS,
168    );
169    Instruction {
170        program_id: crate::id(),
171        accounts: vec![
172            AccountMeta::new(signer, true),
173            AccountMeta::new(bus_0, false),
174            AccountMeta::new(bus_1, false),
175            AccountMeta::new(bus_2, false),
176            AccountMeta::new(bus_3, false),
177            AccountMeta::new(bus_4, false),
178            AccountMeta::new(bus_5, false),
179            AccountMeta::new(bus_6, false),
180            AccountMeta::new(bus_7, false),
181            AccountMeta::new(MINT_ADDRESS, false),
182            AccountMeta::new(TREASURY_ADDRESS, false),
183            AccountMeta::new(treasury_tokens, false),
184            AccountMeta::new_readonly(spl_token::id(), false),
185        ],
186        data: OreInstruction::Reset.to_vec(),
187    }
188}
189
190/// Builds a register instruction.
191pub fn register(signer: Pubkey) -> Instruction {
192    let proof_pda = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id());
193    Instruction {
194        program_id: crate::id(),
195        accounts: vec![
196            AccountMeta::new(signer, true),
197            AccountMeta::new(proof_pda.0, false),
198            AccountMeta::new_readonly(solana_program::system_program::id(), false),
199        ],
200        data: [
201            OreInstruction::Register.to_vec(),
202            RegisterArgs { bump: proof_pda.1 }.to_bytes().to_vec(),
203        ]
204        .concat(),
205    }
206}
207
208/// Builds a mine instruction.
209pub fn mine(signer: Pubkey, bus: Pubkey, hash: Hash, nonce: u64) -> Instruction {
210    let proof = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()).0;
211    Instruction {
212        program_id: crate::id(),
213        accounts: vec![
214            AccountMeta::new(signer, true),
215            AccountMeta::new(bus, false),
216            AccountMeta::new(proof, false),
217            AccountMeta::new_readonly(TREASURY_ADDRESS, false),
218            AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
219        ],
220        data: [
221            OreInstruction::Mine.to_vec(),
222            MineArgs {
223                hash,
224                nonce: nonce.to_le_bytes(),
225            }
226            .to_bytes()
227            .to_vec(),
228        ]
229        .concat(),
230    }
231}
232
233/// Builds a claim instruction.
234pub fn claim(signer: Pubkey, beneficiary: Pubkey, amount: u64) -> Instruction {
235    let proof = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()).0;
236    let treasury_tokens = spl_associated_token_account::get_associated_token_address(
237        &TREASURY_ADDRESS,
238        &MINT_ADDRESS,
239    );
240    Instruction {
241        program_id: crate::id(),
242        accounts: vec![
243            AccountMeta::new(signer, true),
244            AccountMeta::new(beneficiary, false),
245            AccountMeta::new(proof, false),
246            AccountMeta::new(TREASURY_ADDRESS, false),
247            AccountMeta::new(treasury_tokens, false),
248            AccountMeta::new_readonly(spl_token::id(), false),
249        ],
250        data: [
251            OreInstruction::Claim.to_vec(),
252            ClaimArgs {
253                amount: amount.to_le_bytes(),
254            }
255            .to_bytes()
256            .to_vec(),
257        ]
258        .concat(),
259    }
260}
261
262/// Builds an initialize instruction.
263pub fn initialize(signer: Pubkey) -> Instruction {
264    let bus_pdas = [
265        Pubkey::find_program_address(&[BUS, &[0]], &crate::id()),
266        Pubkey::find_program_address(&[BUS, &[1]], &crate::id()),
267        Pubkey::find_program_address(&[BUS, &[2]], &crate::id()),
268        Pubkey::find_program_address(&[BUS, &[3]], &crate::id()),
269        Pubkey::find_program_address(&[BUS, &[4]], &crate::id()),
270        Pubkey::find_program_address(&[BUS, &[5]], &crate::id()),
271        Pubkey::find_program_address(&[BUS, &[6]], &crate::id()),
272        Pubkey::find_program_address(&[BUS, &[7]], &crate::id()),
273    ];
274    let mint_pda = Pubkey::find_program_address(&[MINT, MINT_NOISE.as_slice()], &crate::id());
275    let treasury_pda = Pubkey::find_program_address(&[TREASURY], &crate::id());
276    let treasury_tokens =
277        spl_associated_token_account::get_associated_token_address(&treasury_pda.0, &mint_pda.0);
278    Instruction {
279        program_id: crate::id(),
280        accounts: vec![
281            AccountMeta::new(signer, true),
282            AccountMeta::new(bus_pdas[0].0, false),
283            AccountMeta::new(bus_pdas[1].0, false),
284            AccountMeta::new(bus_pdas[2].0, false),
285            AccountMeta::new(bus_pdas[3].0, false),
286            AccountMeta::new(bus_pdas[4].0, false),
287            AccountMeta::new(bus_pdas[5].0, false),
288            AccountMeta::new(bus_pdas[6].0, false),
289            AccountMeta::new(bus_pdas[7].0, false),
290            AccountMeta::new(mint_pda.0, false),
291            AccountMeta::new(treasury_pda.0, false),
292            AccountMeta::new(treasury_tokens, false),
293            AccountMeta::new_readonly(system_program::id(), false),
294            AccountMeta::new_readonly(spl_token::id(), false),
295            AccountMeta::new_readonly(spl_associated_token_account::id(), false),
296            AccountMeta::new_readonly(sysvar::rent::id(), false),
297        ],
298        data: [
299            OreInstruction::Initialize.to_vec(),
300            InitializeArgs {
301                bus_0_bump: bus_pdas[0].1,
302                bus_1_bump: bus_pdas[1].1,
303                bus_2_bump: bus_pdas[2].1,
304                bus_3_bump: bus_pdas[3].1,
305                bus_4_bump: bus_pdas[4].1,
306                bus_5_bump: bus_pdas[5].1,
307                bus_6_bump: bus_pdas[6].1,
308                bus_7_bump: bus_pdas[7].1,
309                mint_bump: mint_pda.1,
310                treasury_bump: treasury_pda.1,
311            }
312            .to_bytes()
313            .to_vec(),
314        ]
315        .concat(),
316    }
317}
318
319/// Builds an update_admin instruction.
320pub fn update_admin(signer: Pubkey, new_admin: Pubkey) -> Instruction {
321    Instruction {
322        program_id: crate::id(),
323        accounts: vec![
324            AccountMeta::new(signer, true),
325            AccountMeta::new(TREASURY_ADDRESS, false),
326        ],
327        data: [
328            OreInstruction::UpdateAdmin.to_vec(),
329            UpdateAdminArgs { new_admin }.to_bytes().to_vec(),
330        ]
331        .concat(),
332    }
333}
334
335/// Builds an update_difficulty instruction.
336pub fn update_difficulty(signer: Pubkey, new_difficulty: Hash) -> Instruction {
337    Instruction {
338        program_id: crate::id(),
339        accounts: vec![
340            AccountMeta::new(signer, true),
341            AccountMeta::new(TREASURY_ADDRESS, false),
342        ],
343        data: [
344            OreInstruction::UpdateDifficulty.to_vec(),
345            UpdateDifficultyArgs { new_difficulty }.to_bytes().to_vec(),
346        ]
347        .concat(),
348    }
349}