tape/program/
initialize.rs

1use tape_api::prelude::*;
2use solana_program::program_pack::Pack;
3use spl_token::state::Mint;
4use steel::*;
5
6const INITIAL_DIFFICULTY: u32  = 7;
7const INITIAL_REWARD_RATE: u64 = ONE_TAPE;
8
9pub fn process_initialize(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
10    let [
11        signer_info, 
12        spool_0_info, 
13        spool_1_info, 
14        spool_2_info, 
15        spool_3_info, 
16        spool_4_info, 
17        spool_5_info, 
18        spool_6_info, 
19        spool_7_info, 
20        archive_info, 
21        epoch_info, 
22        metadata_info, 
23        mint_info, 
24        treasury_info, 
25        treasury_tokens_info, 
26        system_program_info, 
27        token_program_info, 
28        associated_token_program_info, 
29        metadata_program_info, 
30        rent_sysvar_info,
31    ] = accounts else {
32        return Err(ProgramError::NotEnoughAccountKeys);
33    };
34
35    spool_0_info
36        .is_empty()?
37        .is_writable()?
38        .has_seeds(&[SPOOL, &[0]], &tape_api::ID)?;
39    spool_1_info
40        .is_empty()?
41        .is_writable()?
42        .has_seeds(&[SPOOL, &[1]], &tape_api::ID)?;
43    spool_2_info
44        .is_empty()?
45        .is_writable()?
46        .has_seeds(&[SPOOL, &[2]], &tape_api::ID)?;
47    spool_3_info
48        .is_empty()?
49        .is_writable()?
50        .has_seeds(&[SPOOL, &[3]], &tape_api::ID)?;
51    spool_4_info
52        .is_empty()?
53        .is_writable()?
54        .has_seeds(&[SPOOL, &[4]], &tape_api::ID)?;
55    spool_5_info
56        .is_empty()?
57        .is_writable()?
58        .has_seeds(&[SPOOL, &[5]], &tape_api::ID)?;
59    spool_6_info
60        .is_empty()?
61        .is_writable()?
62        .has_seeds(&[SPOOL, &[6]], &tape_api::ID)?;
63    spool_7_info
64        .is_empty()?
65        .is_writable()?
66        .has_seeds(&[SPOOL, &[7]], &tape_api::ID)?;
67
68    archive_info
69        .is_empty()?
70        .is_writable()?
71        .has_seeds(&[ARCHIVE], &tape_api::ID)?;
72
73    epoch_info
74        .is_empty()?
75        .is_writable()?
76        .has_seeds(&[EPOCH], &tape_api::ID)?;
77
78    // Check mint, metadata, treasury
79    let (mint_address, mint_bump) = mint_pda();
80    let (treasury_address, treasury_bump) = treasury_pda();
81    let (metadata_address, _metadata_bump) = metadata_pda(mint_address);
82
83    assert_eq!(mint_bump, MINT_BUMP);
84    assert_eq!(treasury_bump, TREASURY_BUMP);
85
86    mint_info
87        .is_empty()?
88        .is_writable()?
89        .has_address(&mint_address)?;
90
91    metadata_info
92        .is_empty()?
93        .is_writable()?
94        .has_address(&metadata_address)?;
95
96    treasury_info
97        .is_empty()?
98        .is_writable()?
99        .has_address(&treasury_address)?;
100
101    treasury_tokens_info
102        .is_empty()?
103        .is_writable()?;
104
105    // Check programs and sysvars.
106    system_program_info
107        .is_program(&system_program::ID)?;
108    token_program_info
109        .is_program(&spl_token::ID)?;
110    associated_token_program_info
111        .is_program(&spl_associated_token_account::ID)?;
112
113    solana_program::log::msg!("metadata: {}", metadata_program_info.key);
114
115    metadata_program_info
116        .is_program(&mpl_token_metadata::ID)?;
117    rent_sysvar_info
118        .is_sysvar(&sysvar::rent::ID)?;
119
120    let spool_infos = [
121        spool_0_info, 
122        spool_1_info, 
123        spool_2_info, 
124        spool_3_info, 
125        spool_4_info, 
126        spool_5_info, 
127        spool_6_info,
128        spool_7_info,
129    ];
130
131    // Initialize spools.
132    for i in 0..SPOOL_COUNT {
133        create_program_account::<Spool>(
134            spool_infos[i],
135            system_program_info,
136            signer_info,
137            &tape_api::ID,
138            &[SPOOL, &[i as u8]],
139        )?;
140        let spool = spool_infos[i].as_account_mut::<Spool>(&tape_api::ID)?;
141        spool.id = i as u64;
142        spool.available_rewards = 0;
143        spool.theoretical_rewards = 0;
144    }
145
146    // Initialize epoch.
147    create_program_account::<Epoch>(
148        epoch_info,
149        system_program_info,
150        signer_info,
151        &tape_api::ID,
152        &[EPOCH],
153    )?;
154
155    let epoch = epoch_info.as_account_mut::<Epoch>(&tape_api::ID)?;
156
157    epoch.base_rate     = INITIAL_REWARD_RATE;
158    epoch.difficulty    = INITIAL_DIFFICULTY as u64;
159    epoch.last_epoch_at = 0;
160
161    create_program_account::<Archive>(
162        archive_info,
163        system_program_info,
164        signer_info,
165        &tape_api::ID,
166        &[ARCHIVE],
167    )?;
168
169    let archive = archive_info.as_account_mut::<Archive>(&tape_api::ID)?;
170
171    // No tapes have been created yet.
172    archive.tapes_stored  = 0;
173
174    // Initialize treasury.
175    create_program_account::<Treasury>(
176        treasury_info,
177        system_program_info,
178        signer_info,
179        &tape_api::ID,
180        &[TREASURY],
181    )?;
182
183    // Initialize mint.
184    allocate_account_with_bump(
185        mint_info,
186        system_program_info,
187        signer_info,
188        Mint::LEN,
189        &spl_token::ID,
190        &[MINT, MINT_SEED],
191        MINT_BUMP,
192    )?;
193    initialize_mint_signed_with_bump(
194        mint_info,
195        treasury_info,
196        None,
197        token_program_info,
198        rent_sysvar_info,
199        TOKEN_DECIMALS,
200        &[MINT, MINT_SEED],
201        MINT_BUMP,
202    )?;
203
204    // Initialize mint metadata.
205    mpl_token_metadata::instructions::CreateMetadataAccountV3Cpi {
206        __program: metadata_program_info,
207        metadata: metadata_info,
208        mint: mint_info,
209        mint_authority: treasury_info,
210        payer: signer_info,
211        update_authority: (signer_info, true),
212        system_program: system_program_info,
213        rent: Some(rent_sysvar_info),
214        __args: mpl_token_metadata::instructions::CreateMetadataAccountV3InstructionArgs {
215            data: mpl_token_metadata::types::DataV2 {
216                name: METADATA_NAME.to_string(),
217                symbol: METADATA_SYMBOL.to_string(),
218                uri: METADATA_URI.to_string(),
219                seller_fee_basis_points: 0,
220                creators: None,
221                collection: None,
222                uses: None,
223            },
224            is_mutable: true,
225            collection_details: None,
226        },
227    }
228    .invoke_signed(&[&[TREASURY, &[TREASURY_BUMP]]])?;
229
230    // Initialize treasury token account.
231    create_associated_token_account(
232        signer_info,
233        treasury_info,
234        treasury_tokens_info,
235        mint_info,
236        system_program_info,
237        token_program_info,
238        associated_token_program_info,
239    )?;
240
241    Ok(())
242}