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