1use bytemuck::{Pod, Zeroable};
2use drillx::Solution;
3use num_enum::TryFromPrimitive;
4use solana_program::{
5 instruction::{AccountMeta, Instruction},
6 pubkey::Pubkey,
7 system_program, sysvar,
8};
9
10use crate::{
11 consts::*,
12 utils::{impl_instruction_from_bytes, impl_to_bytes},
13};
14
15#[repr(u8)]
16#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
17#[rustfmt::skip]
18pub enum SmelterInstruction {
19 Claim = 0,
21 Close = 1,
22 Smelt = 2,
23 Open = 3,
24 Reset = 4,
25 Stake = 5,
26 Update = 6,
27
28 Initialize = 100,
30}
31
32impl SmelterInstruction {
33 pub fn to_vec(&self) -> Vec<u8> {
34 vec![*self as u8]
35 }
36}
37
38#[repr(C)]
39#[derive(Clone, Copy, Debug, Pod, Zeroable)]
40pub struct InitializeArgs {
41 pub bus_0_bump: u8,
42 pub bus_1_bump: u8,
43 pub bus_2_bump: u8,
44 pub bus_3_bump: u8,
45 pub bus_4_bump: u8,
46 pub bus_5_bump: u8,
47 pub bus_6_bump: u8,
48 pub bus_7_bump: u8,
49 pub config_bump: u8,
50 pub metadata_bump: u8,
51 pub mint_bump: u8,
52 pub treasury_bump: u8,
53}
54
55#[repr(C)]
56#[derive(Clone, Copy, Debug, Pod, Zeroable)]
57pub struct OpenArgs {
58 pub bump: u8,
59}
60
61#[repr(C)]
62#[derive(Clone, Copy, Debug, Pod, Zeroable)]
63pub struct MineArgs {
64 pub digest: [u8; 16],
65 pub nonce: [u8; 8],
66}
67
68#[repr(C)]
69#[derive(Clone, Copy, Debug, Pod, Zeroable)]
70pub struct ClaimArgs {
71 pub amount: [u8; 8],
72}
73
74#[repr(C)]
75#[derive(Clone, Copy, Debug, Pod, Zeroable)]
76pub struct StakeArgs {
77 pub amount: [u8; 8],
78}
79
80#[repr(C)]
81#[derive(Clone, Copy, Debug, Pod, Zeroable)]
82pub struct UpgradeArgs {
83 pub amount: [u8; 8],
84}
85
86impl_to_bytes!(InitializeArgs);
87impl_to_bytes!(OpenArgs);
88impl_to_bytes!(MineArgs);
89impl_to_bytes!(ClaimArgs);
90impl_to_bytes!(StakeArgs);
91impl_to_bytes!(UpgradeArgs);
92
93impl_instruction_from_bytes!(InitializeArgs);
94impl_instruction_from_bytes!(OpenArgs);
95impl_instruction_from_bytes!(MineArgs);
96impl_instruction_from_bytes!(ClaimArgs);
97impl_instruction_from_bytes!(StakeArgs);
98impl_instruction_from_bytes!(UpgradeArgs);
99
100pub fn auth(proof: Pubkey) -> Instruction {
102 Instruction {
103 program_id: NOOP_PROGRAM_ID,
104 accounts: vec![],
105 data: proof.to_bytes().to_vec(),
106 }
107}
108
109pub fn claim(signer: Pubkey, beneficiary: Pubkey, amount: u64) -> Instruction {
111 let proof = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()).0;
112 let treasury_tokens = spl_associated_token_account::get_associated_token_address(
113 &TREASURY_ADDRESS,
114 &MINT_ADDRESS,
115 );
116 Instruction {
117 program_id: crate::id(),
118 accounts: vec![
119 AccountMeta::new(signer, true),
120 AccountMeta::new(beneficiary, false),
121 AccountMeta::new(proof, false),
122 AccountMeta::new_readonly(TREASURY_ADDRESS, false),
123 AccountMeta::new(treasury_tokens, false),
124 AccountMeta::new_readonly(spl_token::id(), false),
125 ],
126 data: [
127 SmelterInstruction::Claim.to_vec(),
128 ClaimArgs {
129 amount: amount.to_le_bytes(),
130 }
131 .to_bytes()
132 .to_vec(),
133 ]
134 .concat(),
135 }
136}
137
138pub fn close(signer: Pubkey) -> Instruction {
140 let proof_pda = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id());
141 Instruction {
142 program_id: crate::id(),
143 accounts: vec![
144 AccountMeta::new(signer, true),
145 AccountMeta::new(proof_pda.0, false),
146 AccountMeta::new_readonly(solana_program::system_program::id(), false),
147 ],
148 data: SmelterInstruction::Close.to_vec(),
149 }
150}
151
152pub fn smelt(
154 signer: Pubkey,
155 proof_authority: Pubkey,
156 bus: Pubkey,
157 solution: Solution,
158) -> Instruction {
159 let proof = Pubkey::find_program_address(&[PROOF, proof_authority.as_ref()], &crate::id()).0;
160 let ore_token_address = spl_associated_token_account::get_associated_token_address(
161 &signer,
162 &ORE_MINT_ADDRESS,
163 );
164 let coal_token_address = spl_associated_token_account::get_associated_token_address(
165 &signer,
166 &COAL_MINT_ADDRESS,
167 );
168
169 Instruction {
170 program_id: crate::id(),
171 accounts: vec![
172 AccountMeta::new(signer, true),
173 AccountMeta::new(bus, false),
174 AccountMeta::new_readonly(CONFIG_ADDRESS, false),
175 AccountMeta::new(proof, false),
176 AccountMeta::new(COAL_MINT_ADDRESS, false),
177 AccountMeta::new(coal_token_address, false),
178 AccountMeta::new(ore_token_address, false),
179 AccountMeta::new(TREASURY_ORE_TOKENS_ADDRESS, false),
180 AccountMeta::new_readonly(spl_token::id(), false),
181 AccountMeta::new_readonly(sysvar::instructions::id(), false),
182 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
183 ],
184 data: [
185 SmelterInstruction::Smelt.to_vec(),
186 MineArgs {
187 digest: solution.d,
188 nonce: solution.n,
189 }
190 .to_bytes()
191 .to_vec(),
192 ]
193 .concat(),
194 }
195}
196
197pub fn open(signer: Pubkey, miner: Pubkey, payer: Pubkey) -> Instruction {
199 let proof_pda = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id());
200 Instruction {
201 program_id: crate::id(),
202 accounts: vec![
203 AccountMeta::new(signer, true),
204 AccountMeta::new_readonly(miner, false),
205 AccountMeta::new(payer, true),
206 AccountMeta::new(proof_pda.0, false),
207 AccountMeta::new_readonly(solana_program::system_program::id(), false),
208 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
209 ],
210 data: [
211 SmelterInstruction::Open.to_vec(),
212 OpenArgs { bump: proof_pda.1 }.to_bytes().to_vec(),
213 ]
214 .concat(),
215 }
216}
217
218pub fn reset(signer: Pubkey) -> Instruction {
220 let treasury_tokens = spl_associated_token_account::get_associated_token_address(
221 &TREASURY_ADDRESS,
222 &MINT_ADDRESS,
223 );
224 Instruction {
225 program_id: crate::id(),
226 accounts: vec![
227 AccountMeta::new(signer, true),
228 AccountMeta::new(BUS_ADDRESSES[0], false),
229 AccountMeta::new(BUS_ADDRESSES[1], false),
230 AccountMeta::new(BUS_ADDRESSES[2], false),
231 AccountMeta::new(BUS_ADDRESSES[3], false),
232 AccountMeta::new(BUS_ADDRESSES[4], false),
233 AccountMeta::new(BUS_ADDRESSES[5], false),
234 AccountMeta::new(BUS_ADDRESSES[6], false),
235 AccountMeta::new(BUS_ADDRESSES[7], false),
236 AccountMeta::new(CONFIG_ADDRESS, false),
237 AccountMeta::new(MINT_ADDRESS, false),
238 AccountMeta::new(TREASURY_ADDRESS, false),
239 AccountMeta::new(treasury_tokens, false),
240 AccountMeta::new_readonly(spl_token::id(), false),
241 ],
242 data: SmelterInstruction::Reset.to_vec(),
243 }
244}
245
246pub fn stake(signer: Pubkey, sender: Pubkey, amount: u64) -> Instruction {
248 let proof = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()).0;
249 let treasury_tokens = spl_associated_token_account::get_associated_token_address(
250 &TREASURY_ADDRESS,
251 &MINT_ADDRESS,
252 );
253 Instruction {
254 program_id: crate::id(),
255 accounts: vec![
256 AccountMeta::new(signer, true),
257 AccountMeta::new(proof, false),
258 AccountMeta::new(sender, false),
259 AccountMeta::new(treasury_tokens, false),
260 AccountMeta::new_readonly(spl_token::id(), false),
261 ],
262 data: [
263 SmelterInstruction::Stake.to_vec(),
264 StakeArgs {
265 amount: amount.to_le_bytes(),
266 }
267 .to_bytes()
268 .to_vec(),
269 ]
270 .concat(),
271 }
272}
273
274pub fn update(signer: Pubkey, miner: Pubkey) -> Instruction {
276 let proof = Pubkey::find_program_address(&[PROOF, signer.as_ref()], &crate::id()).0;
277 Instruction {
278 program_id: crate::id(),
279 accounts: vec![
280 AccountMeta::new(signer, true),
281 AccountMeta::new_readonly(miner, false),
282 AccountMeta::new(proof, false),
283 ],
284 data: SmelterInstruction::Update.to_vec(),
285 }
286}
287
288pub fn initialize(signer: Pubkey) -> Instruction {
290 let bus_pdas = [
291 Pubkey::find_program_address(&[BUS, &[0]], &crate::id()),
292 Pubkey::find_program_address(&[BUS, &[1]], &crate::id()),
293 Pubkey::find_program_address(&[BUS, &[2]], &crate::id()),
294 Pubkey::find_program_address(&[BUS, &[3]], &crate::id()),
295 Pubkey::find_program_address(&[BUS, &[4]], &crate::id()),
296 Pubkey::find_program_address(&[BUS, &[5]], &crate::id()),
297 Pubkey::find_program_address(&[BUS, &[6]], &crate::id()),
298 Pubkey::find_program_address(&[BUS, &[7]], &crate::id()),
299 ];
300 let config_pda = Pubkey::find_program_address(&[CONFIG], &crate::id());
301 let mint_pda = Pubkey::find_program_address(&[MINT, MINT_NOISE.as_slice()], &crate::id());
302
303 let treasury_pda = Pubkey::find_program_address(&[TREASURY], &crate::id());
304 let treasury_tokens =
305 spl_associated_token_account::get_associated_token_address(&treasury_pda.0, &mint_pda.0);
306 let ore_treasury_tokens =
307 spl_associated_token_account::get_associated_token_address(&treasury_pda.0, &ORE_MINT_ADDRESS);
308 let metadata_pda = Pubkey::find_program_address(
309 &[
310 METADATA,
311 mpl_token_metadata::ID.as_ref(),
312 mint_pda.0.as_ref(),
313 ],
314 &mpl_token_metadata::ID,
315 );
316 Instruction {
317 program_id: crate::id(),
318 accounts: vec![
319 AccountMeta::new(signer, true),
320 AccountMeta::new(bus_pdas[0].0, false),
321 AccountMeta::new(bus_pdas[1].0, false),
322 AccountMeta::new(bus_pdas[2].0, false),
323 AccountMeta::new(bus_pdas[3].0, false),
324 AccountMeta::new(bus_pdas[4].0, false),
325 AccountMeta::new(bus_pdas[5].0, false),
326 AccountMeta::new(bus_pdas[6].0, false),
327 AccountMeta::new(bus_pdas[7].0, false),
328 AccountMeta::new(config_pda.0, false),
329 AccountMeta::new(metadata_pda.0, false),
330 AccountMeta::new(mint_pda.0, false),
331 AccountMeta::new(ORE_MINT_ADDRESS, false),
332 AccountMeta::new(treasury_pda.0, false),
333 AccountMeta::new(treasury_tokens, false),
334 AccountMeta::new(ore_treasury_tokens, false),
335 AccountMeta::new_readonly(system_program::id(), false),
336 AccountMeta::new_readonly(spl_token::id(), false),
337 AccountMeta::new_readonly(spl_associated_token_account::id(), false),
338 AccountMeta::new_readonly(mpl_token_metadata::ID, false),
339 AccountMeta::new_readonly(sysvar::rent::id(), false),
340 ],
341 data: [
342 SmelterInstruction::Initialize.to_vec(),
343 InitializeArgs {
344 bus_0_bump: bus_pdas[0].1,
345 bus_1_bump: bus_pdas[1].1,
346 bus_2_bump: bus_pdas[2].1,
347 bus_3_bump: bus_pdas[3].1,
348 bus_4_bump: bus_pdas[4].1,
349 bus_5_bump: bus_pdas[5].1,
350 bus_6_bump: bus_pdas[6].1,
351 bus_7_bump: bus_pdas[7].1,
352 config_bump: config_pda.1,
353 metadata_bump: metadata_pda.1,
354 mint_bump: mint_pda.1,
355 treasury_bump: treasury_pda.1,
356 }
357 .to_bytes()
358 .to_vec(),
359 ]
360 .concat(),
361 }
362}