1use std::io::Error;
2use std::mem::size_of;
3use borsh::{BorshDeserialize, BorshSerialize};
4use solana_program::{
5 instruction::{AccountMeta, Instruction},
6 pubkey::Pubkey,
7 system_program,
8 sysvar
9};
10use mpl_core::programs::MPL_CORE_ID;
11
12use crate::consts::*;
13
14#[repr(C)]
15#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
16pub struct MintV1Args {
17 pub resource: String,
18 pub config_bump: u8,
19 pub collection_authority_bump: u8,
20
21}
22
23#[repr(C)]
24#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
25pub struct NewV1Args {
26 pub name: String,
27 pub uri: String,
28 pub multiplier: u64,
29 pub durability: u64,
30 pub ingredients: [Pubkey; 3],
31 pub amounts: [u64; 3],
32 pub config_bump: u8,
33 pub collection_authority_bump: u8,
34}
35
36#[repr(C)]
37#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
38pub struct InitializeArgs {
39 pub treasury_bump: u8,
40}
41
42#[repr(C)]
43#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
44pub struct VerifyArgs {
45 pub collection_authority_bump: u8,
46}
47
48#[repr(C)]
49#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
50pub struct InitializeEnhanceArgs {
51 pub enhancer_bump: u8,
52}
53
54#[repr(C)]
55#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
56pub struct EnhanceArgs {
57 pub enhancer_bump: u8,
58 pub collection_authority_bump: u8,
59}
60
61#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)]
62#[rustfmt::skip]
63pub enum ForgeInstruction {
64 MintV1(MintV1Args),
66 NewV1(NewV1Args),
68 Initialize(InitializeArgs),
69 Verify(VerifyArgs),
70 InitializeEnhance(InitializeEnhanceArgs),
71 Enhance(EnhanceArgs),
72}
73
74impl ForgeInstruction {
75 pub fn try_to_vec(&self) -> Result<Vec<u8>, Error> {
76 let mut buf = Vec::with_capacity(size_of::<ForgeInstruction>());
77 self.serialize(&mut buf)?;
78 Ok(buf)
79 }
80}
81
82pub fn initialize(signer: Pubkey) -> Instruction {
83 let initialize_args = ForgeInstruction::Initialize(InitializeArgs {
84 treasury_bump: TREASURY_BUMP,
85 });
86
87 Instruction {
88 program_id: crate::id(),
89 accounts: vec![
90 AccountMeta::new(signer, true),
91 AccountMeta::new(TREASURY_ADDRESS, false),
92 AccountMeta::new_readonly(system_program::id(), false),
93 ],
94 data: [initialize_args.try_to_vec().unwrap()].concat(),
95 }
96}
97
98pub fn verify(signer: Pubkey, destination: Pubkey) -> Instruction {
99 let (collection_authority, collection_authority_bump) = Pubkey::find_program_address(&[COLLECTION_AUTHORITY_SEED], &crate::id());
100
101 let verify_args: ForgeInstruction = ForgeInstruction::Verify(VerifyArgs {
102 collection_authority_bump,
103 });
104
105 Instruction {
106 program_id: crate::id(),
107 accounts: vec![
108 AccountMeta::new(signer, true),
109 AccountMeta::new(collection_authority, false),
110 AccountMeta::new(destination, false),
111 AccountMeta::new_readonly(system_program::id(), false),
112 ],
113 data: [verify_args.try_to_vec().unwrap()].concat(),
114 }
115}
116
117pub fn new(signer: Pubkey, collection: Pubkey) -> Instruction {
119 let (collection_authority, collection_authority_bump) = Pubkey::find_program_address(&[COLLECTION_AUTHORITY_SEED], &crate::id());
120 let (config, config_bump) = Pubkey::find_program_address(&[CONFIG_SEED, collection.as_ref()], &crate::id());
121
122 let new_v1_args = ForgeInstruction::NewV1(NewV1Args {
123 name: "Miner's Pickaxe".to_string(),
124 uri: "https://minechain.gg/metadata.pickaxe.json".to_string(),
125 multiplier: 70, durability: 1000, amounts: [ONE_TOKEN.saturating_mul(1), 0, 0],
128 ingredients: [COAL_MINT_ADDRESS, solana_program::system_program::ID, solana_program::system_program::ID],
129 config_bump,
130 collection_authority_bump,
131 });
132
133 Instruction {
134 program_id: crate::id(),
135 accounts: vec![
136 AccountMeta::new(signer, true),
137 AccountMeta::new(collection, true),
138 AccountMeta::new_readonly(collection_authority, false),
139 AccountMeta::new(config, false),
140 AccountMeta::new_readonly(MPL_CORE_ID, false),
141 AccountMeta::new_readonly(spl_token::id(), false),
142 AccountMeta::new_readonly(spl_associated_token_account::id(), false),
143 AccountMeta::new(system_program::id(), false),
144 AccountMeta::new_readonly(COAL_MINT_ADDRESS, false),
145 AccountMeta::new_readonly(WOOD_MINT_ADDRESS, false),
146 ],
147 data: [new_v1_args.try_to_vec().unwrap()].concat(),
148 }
149}
150
151pub fn mint(signer: Pubkey, collection: Pubkey, mint: Pubkey, resource: String) -> Instruction {
153 let (collection_authority, collection_authority_bump) = Pubkey::find_program_address(&[COLLECTION_AUTHORITY_SEED], &crate::id());
154 let (config, config_bump) = Pubkey::find_program_address(&[CONFIG_SEED, collection.as_ref()], &crate::id());
155
156 let ingot_tokens = spl_associated_token_account::get_associated_token_address(
157 &signer,
158 &INGOT_MINT_ADDEESS,
159 );
160 let wood_tokens = spl_associated_token_account::get_associated_token_address(
161 &signer,
162 &WOOD_MINT_ADDRESS,
163 );
164
165 let mint_v1_args: ForgeInstruction = ForgeInstruction::MintV1(MintV1Args {
166 resource,
167 config_bump,
168 collection_authority_bump,
169 });
170
171 Instruction {
172 program_id: crate::id(),
173 accounts: vec![
174 AccountMeta::new(signer, true),
175 AccountMeta::new(mint, true),
176 AccountMeta::new(collection, false),
177 AccountMeta::new_readonly(collection_authority, false),
178 AccountMeta::new_readonly(config, false),
179 AccountMeta::new_readonly(MPL_CORE_ID, false),
180 AccountMeta::new_readonly(spl_token::id(), false),
181 AccountMeta::new(system_program::id(), false),
182 AccountMeta::new(INGOT_MINT_ADDEESS, false),
183 AccountMeta::new(ingot_tokens, false),
184 AccountMeta::new(WOOD_MINT_ADDRESS, false),
185 AccountMeta::new(wood_tokens, false),
186 ],
187 data: [mint_v1_args.try_to_vec().unwrap()].concat(),
188 }
189}
190
191pub fn init_enhance(signer: Pubkey, asset: Pubkey) -> Instruction {
193 let (enhancer, enhancer_bump) = Pubkey::find_program_address(&[ENHANCER_SEED, signer.as_ref(), asset.as_ref()], &crate::id());
194
195 let chromium_tokens = spl_associated_token_account::get_associated_token_address(
196 &signer,
197 &CHROMIUM_MINT_ADDRESS,
198 );
199
200 let init_enhance_args: ForgeInstruction = ForgeInstruction::InitializeEnhance(InitializeEnhanceArgs {
201 enhancer_bump,
202 });
203
204 Instruction {
205 program_id: crate::id(),
206 accounts: vec![
207 AccountMeta::new(signer, true),
208 AccountMeta::new_readonly(asset, false),
209 AccountMeta::new(enhancer, false),
210 AccountMeta::new(CHROMIUM_MINT_ADDRESS, false),
211 AccountMeta::new(chromium_tokens, false),
212 AccountMeta::new_readonly(spl_token::id(), false),
213 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
214 AccountMeta::new_readonly(system_program::id(), false),
215 ],
216 data: [init_enhance_args.try_to_vec().unwrap()].concat(),
217 }
218}
219
220pub fn enhance(signer: Pubkey, asset: Pubkey, new_mint: Pubkey, collection: Pubkey) -> Instruction {
222 let (collection_authority, collection_authority_bump) = Pubkey::find_program_address(&[COLLECTION_AUTHORITY_SEED], &crate::id());
223 let (enhancer, enhancer_bump) = Pubkey::find_program_address(&[ENHANCER_SEED, signer.as_ref(), asset.as_ref()], &crate::id());
224
225 let enhance_args: ForgeInstruction = ForgeInstruction::Enhance(EnhanceArgs {
226 enhancer_bump,
227 collection_authority_bump,
228 });
229
230 Instruction {
231 program_id: crate::id(),
232 accounts: vec![
233 AccountMeta::new(signer, true),
234 AccountMeta::new(new_mint, true),
235 AccountMeta::new(asset, false),
236 AccountMeta::new(collection, false),
237 AccountMeta::new_readonly(collection_authority, false),
238 AccountMeta::new(enhancer, false),
239 AccountMeta::new_readonly(MPL_CORE_ID, false),
240 AccountMeta::new_readonly(system_program::id(), false),
241 AccountMeta::new_readonly(sysvar::slot_hashes::id(), false),
242 ],
243 data: [enhance_args.try_to_vec().unwrap()].concat(),
244 }
245}