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