forge_api/
instruction.rs

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    // User
65    MintV1(MintV1Args),
66    // Admin
67    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
117/// Builds a new instruction.
118pub 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, // 70% bonus
126        durability: 1000, // 1000 uses
127        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
151// signer, mint_info, collection_info, collection_authority, mpl_core_program, system_program
152pub 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
191// signer, asset_info, enhancer_info, chromium_mint_info, chromium_tokens_info, slot_hashes_sysvar, system_program
192pub 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
220// signer, asset_info, new_mint_info, collection_info, collection_authority, enhancer_info, mpl_core_program, system_program, slot_hashes_sysvar
221pub 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}