1use crate::assert_with_msg;
2use solana_program::{
3 account_info::{next_account_info, AccountInfo},
4 program_error::ProgramError,
5 system_program,
6};
7
8pub struct InitializeMint<'a, 'info> {
9 pub mint: &'a AccountInfo<'info>,
10 pub payer: &'a AccountInfo<'info>,
11 pub upstream_authority: &'a AccountInfo<'info>,
12 pub system_program: &'a AccountInfo<'info>,
13 pub token_program: &'a AccountInfo<'info>,
14}
15
16impl<'a, 'info> InitializeMint<'a, 'info> {
17 pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
18 let account_iter = &mut accounts.iter();
19 let ctx = Self {
20 mint: next_account_info(account_iter)?,
21 payer: next_account_info(account_iter)?,
22 upstream_authority: next_account_info(account_iter)?,
23 system_program: next_account_info(account_iter)?,
24 token_program: next_account_info(account_iter)?,
25 };
26 assert_with_msg(
27 ctx.mint.data_is_empty(),
28 ProgramError::InvalidAccountData,
29 "Mint account must be uninitialized",
30 )?;
31 assert_with_msg(
32 ctx.mint.owner == &system_program::id(),
33 ProgramError::IllegalOwner,
34 "Mint account must be owned by the System Program when uninitialized",
35 )?;
36 assert_with_msg(
37 ctx.token_program.key == &spl_token::id(),
38 ProgramError::InvalidInstructionData,
39 "Invalid key supplied for Token Program",
40 )?;
41 assert_with_msg(
42 ctx.system_program.key == &system_program::id(),
43 ProgramError::InvalidInstructionData,
44 "Invalid key supplied for System Program",
45 )?;
46 assert_with_msg(
47 ctx.mint.is_writable,
48 ProgramError::InvalidInstructionData,
49 "Mint account must be writable",
50 )?;
51 assert_with_msg(
52 ctx.payer.is_writable,
53 ProgramError::InvalidInstructionData,
54 "Payer account must be writable (lamport balance will change)",
55 )?;
56 assert_with_msg(
57 ctx.payer.is_signer,
58 ProgramError::MissingRequiredSignature,
59 "Payer must sign for initialization",
60 )?;
61 Ok(ctx)
62 }
63}
64
65pub struct InitializeAccount<'a, 'info> {
66 pub token_account: &'a AccountInfo<'info>,
67 pub owner: &'a AccountInfo<'info>,
68 pub payer: &'a AccountInfo<'info>,
69 pub upstream_authority: &'a AccountInfo<'info>,
70 pub freeze_authority: &'a AccountInfo<'info>,
71 pub mint: &'a AccountInfo<'info>,
72 pub system_program: &'a AccountInfo<'info>,
73 pub associated_token_program: &'a AccountInfo<'info>,
74 pub token_program: &'a AccountInfo<'info>,
75}
76
77impl<'a, 'info> InitializeAccount<'a, 'info> {
78 pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
79 let account_iter = &mut accounts.iter();
80 let ctx = Self {
81 token_account: next_account_info(account_iter)?,
82 owner: next_account_info(account_iter)?,
83 payer: next_account_info(account_iter)?,
84 upstream_authority: next_account_info(account_iter)?,
85 freeze_authority: next_account_info(account_iter)?,
86 mint: next_account_info(account_iter)?,
87 system_program: next_account_info(account_iter)?,
88 associated_token_program: next_account_info(account_iter)?,
89 token_program: next_account_info(account_iter)?,
90 };
91 assert_with_msg(
92 ctx.token_account.data_is_empty(),
93 ProgramError::InvalidAccountData,
94 "Token account must be uninitialized",
95 )?;
96 assert_with_msg(
97 ctx.token_account.owner == &system_program::id(),
98 ProgramError::IllegalOwner,
99 "Token account must be owned by System Program when uninitialized",
100 )?;
101 assert_with_msg(
102 ctx.mint.owner == ctx.token_program.key,
103 ProgramError::IllegalOwner,
104 "Mint account must be owned by the Token Program",
105 )?;
106 assert_with_msg(
107 ctx.token_program.key == &spl_token::id(),
108 ProgramError::InvalidInstructionData,
109 "Invalid key supplied for Token Program",
110 )?;
111 assert_with_msg(
112 ctx.system_program.key == &system_program::id(),
113 ProgramError::InvalidInstructionData,
114 "Invalid key supplied for System Program",
115 )?;
116 assert_with_msg(
117 ctx.associated_token_program.key == &spl_associated_token_account::id(),
118 ProgramError::InvalidInstructionData,
119 "Invalid key supplied for Associataed Token Program",
120 )?;
121 assert_with_msg(
122 ctx.token_account.is_writable,
123 ProgramError::InvalidInstructionData,
124 "Token account must be writable",
125 )?;
126 assert_with_msg(
127 ctx.payer.is_writable,
128 ProgramError::InvalidInstructionData,
129 "Payer account must be writable (lamport balance will change)",
130 )?;
131 assert_with_msg(
132 ctx.payer.is_signer,
133 ProgramError::MissingRequiredSignature,
134 "Payer must sign for initialization",
135 )?;
136 assert_with_msg(
137 ctx.upstream_authority.is_signer,
138 ProgramError::MissingRequiredSignature,
139 "Freeze authority must sign for initialization",
140 )?;
141 Ok(ctx)
142 }
143}
144
145pub struct Mint<'a, 'info> {
146 pub mint: &'a AccountInfo<'info>,
147 pub token_account: &'a AccountInfo<'info>,
148 pub upstream_authority: &'a AccountInfo<'info>,
149 pub freeze_and_mint_authority: &'a AccountInfo<'info>,
150 pub token_program: &'a AccountInfo<'info>,
151}
152
153impl<'a, 'info> Mint<'a, 'info> {
154 pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
155 let account_iter = &mut accounts.iter();
156 let ctx = Self {
157 mint: next_account_info(account_iter)?,
158 token_account: next_account_info(account_iter)?,
159 upstream_authority: next_account_info(account_iter)?,
160 freeze_and_mint_authority: next_account_info(account_iter)?,
161 token_program: next_account_info(account_iter)?,
162 };
163 assert_with_msg(
164 ctx.mint.owner == ctx.token_program.key,
165 ProgramError::IllegalOwner,
166 "Mint account must be owned by the Token Program",
167 )?;
168 assert_with_msg(
169 ctx.token_account.owner == ctx.token_program.key,
170 ProgramError::IllegalOwner,
171 "Token account must be owned by the Token Program",
172 )?;
173 assert_with_msg(
174 ctx.token_program.key == &spl_token::id(),
175 ProgramError::InvalidInstructionData,
176 "Invalid key supplied for Token Program",
177 )?;
178 assert_with_msg(
179 ctx.mint.is_writable,
180 ProgramError::InvalidInstructionData,
181 "Mint must be writable",
182 )?;
183 assert_with_msg(
184 ctx.token_account.is_writable,
185 ProgramError::InvalidInstructionData,
186 "Token Account must be writable",
187 )?;
188 assert_with_msg(
189 ctx.upstream_authority.is_signer,
190 ProgramError::MissingRequiredSignature,
191 "Freeze authority must sign for modification",
192 )?;
193 Ok(ctx)
194 }
195}
196
197pub struct Burn<'a, 'info> {
198 pub mint: &'a AccountInfo<'info>,
199 pub token_account: &'a AccountInfo<'info>,
200 pub owner: &'a AccountInfo<'info>,
201 pub upstream_authority: &'a AccountInfo<'info>,
202 pub freeze_authority: &'a AccountInfo<'info>,
203 pub token_program: &'a AccountInfo<'info>,
204}
205
206impl<'a, 'info> Burn<'a, 'info> {
207 pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
208 let account_iter = &mut accounts.iter();
209 let ctx = Self {
210 mint: next_account_info(account_iter)?,
211 token_account: next_account_info(account_iter)?,
212 owner: next_account_info(account_iter)?,
213 upstream_authority: next_account_info(account_iter)?,
214 freeze_authority: next_account_info(account_iter)?,
215 token_program: next_account_info(account_iter)?,
216 };
217 assert_with_msg(
218 ctx.mint.owner == ctx.token_program.key,
219 ProgramError::IllegalOwner,
220 "Mint account must be owned by the Token Program",
221 )?;
222 assert_with_msg(
223 ctx.token_account.owner == ctx.token_program.key,
224 ProgramError::IllegalOwner,
225 "Token account must be owned by the Token Program",
226 )?;
227 assert_with_msg(
228 ctx.token_program.key == &spl_token::id(),
229 ProgramError::InvalidInstructionData,
230 "Invalid key supplied for Token Program",
231 )?;
232 assert_with_msg(
233 ctx.mint.is_writable,
234 ProgramError::InvalidInstructionData,
235 "Mint must be writable",
236 )?;
237 assert_with_msg(
238 ctx.token_account.is_writable,
239 ProgramError::InvalidInstructionData,
240 "Token Account must be writable",
241 )?;
242 assert_with_msg(
243 ctx.upstream_authority.is_signer,
244 ProgramError::MissingRequiredSignature,
245 "Freeze authority must sign for modification",
246 )?;
247 assert_with_msg(
248 ctx.owner.is_signer,
249 ProgramError::MissingRequiredSignature,
250 "Owner must sign for modification",
251 )?;
252 Ok(ctx)
253 }
254}
255
256pub struct Transfer<'a, 'info> {
257 pub src_account: &'a AccountInfo<'info>,
258 pub dst_account: &'a AccountInfo<'info>,
259 pub mint: &'a AccountInfo<'info>,
260 pub owner: &'a AccountInfo<'info>,
261 pub upstream_authority: &'a AccountInfo<'info>,
262 pub freeze_authority: &'a AccountInfo<'info>,
263 pub token_program: &'a AccountInfo<'info>,
264}
265
266impl<'a, 'info> Transfer<'a, 'info> {
267 pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
268 let account_iter = &mut accounts.iter();
269 let ctx = Self {
270 src_account: next_account_info(account_iter)?,
271 dst_account: next_account_info(account_iter)?,
272 mint: next_account_info(account_iter)?,
273 owner: next_account_info(account_iter)?,
274 upstream_authority: next_account_info(account_iter)?,
275 freeze_authority: next_account_info(account_iter)?,
276 token_program: next_account_info(account_iter)?,
277 };
278 assert_with_msg(
279 ctx.mint.owner == &spl_token::id(),
280 ProgramError::IllegalOwner,
281 "Mint account must be owned by the Token Program",
282 )?;
283 assert_with_msg(
284 ctx.src_account.owner == &spl_token::id(),
285 ProgramError::IllegalOwner,
286 "Source token account must be owned by the Token Program",
287 )?;
288 assert_with_msg(
289 ctx.dst_account.owner == &spl_token::id(),
290 ProgramError::IllegalOwner,
291 "Destination token account must be owned by the Token Program",
292 )?;
293 assert_with_msg(
294 ctx.token_program.key == &spl_token::id(),
295 ProgramError::InvalidInstructionData,
296 "Invalid key supplied for Token Program",
297 )?;
298 assert_with_msg(
299 ctx.src_account.is_writable,
300 ProgramError::InvalidInstructionData,
301 "Source token account must be writable",
302 )?;
303 assert_with_msg(
304 ctx.dst_account.is_writable,
305 ProgramError::InvalidInstructionData,
306 "Destination token account must be writable",
307 )?;
308 assert_with_msg(
309 ctx.owner.is_signer,
310 ProgramError::MissingRequiredSignature,
311 "Owner must sign for modification",
312 )?;
313 assert_with_msg(
314 ctx.upstream_authority.is_signer,
315 ProgramError::MissingRequiredSignature,
316 "Freeze authority must sign for modification",
317 )?;
318 Ok(ctx)
319 }
320}
321
322pub struct Close<'a, 'info> {
323 pub token_account: &'a AccountInfo<'info>,
324 pub dst_account: &'a AccountInfo<'info>,
325 pub mint: &'a AccountInfo<'info>,
326 pub owner: &'a AccountInfo<'info>,
327 pub upstream_authority: &'a AccountInfo<'info>,
328 pub freeze_authority: &'a AccountInfo<'info>,
329 pub token_program: &'a AccountInfo<'info>,
330}
331
332impl<'a, 'info> Close<'a, 'info> {
333 pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
334 let account_iter = &mut accounts.iter();
335 let ctx = Self {
336 token_account: next_account_info(account_iter)?,
337 dst_account: next_account_info(account_iter)?,
338 mint: next_account_info(account_iter)?,
339 owner: next_account_info(account_iter)?,
340 upstream_authority: next_account_info(account_iter)?,
341 freeze_authority: next_account_info(account_iter)?,
342 token_program: next_account_info(account_iter)?,
343 };
344 assert_with_msg(
345 ctx.mint.owner == ctx.token_program.key,
346 ProgramError::IllegalOwner,
347 "Mint account must be owned by the Token Program",
348 )?;
349 assert_with_msg(
350 ctx.token_account.owner == ctx.token_program.key,
351 ProgramError::IllegalOwner,
352 "Token account must be owned by the Token Program",
353 )?;
354 assert_with_msg(
355 ctx.dst_account.owner == &system_program::id(),
356 ProgramError::IllegalOwner,
357 "Destination account must be owned by the System Program",
358 )?;
359 assert_with_msg(
360 ctx.token_program.key == &spl_token::id(),
361 ProgramError::InvalidInstructionData,
362 "Invalid key supplied for Token Program",
363 )?;
364 assert_with_msg(
365 ctx.token_account.is_writable,
366 ProgramError::InvalidInstructionData,
367 "Token Account must be writable",
368 )?;
369 assert_with_msg(
370 ctx.dst_account.is_writable,
371 ProgramError::InvalidInstructionData,
372 "Destination account must be writable",
373 )?;
374 assert_with_msg(
375 ctx.owner.is_signer,
376 ProgramError::MissingRequiredSignature,
377 "Owner must sign for close",
378 )?;
379 assert_with_msg(
380 ctx.upstream_authority.is_signer,
381 ProgramError::MissingRequiredSignature,
382 "Freeze authority must sign for close",
383 )?;
384 Ok(ctx)
385 }
386}
387
388pub struct Approve<'a, 'info> {
389 pub mint: &'a AccountInfo<'info>,
390 pub token_account: &'a AccountInfo<'info>,
391 pub owner: &'a AccountInfo<'info>,
392 pub upstream_authority: &'a AccountInfo<'info>,
393 pub delegate: &'a AccountInfo<'info>,
394 pub freeze_authority: &'a AccountInfo<'info>,
395 pub token_program: &'a AccountInfo<'info>,
396}
397
398impl<'a, 'info> Approve<'a, 'info> {
399 pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
400 let account_iter = &mut accounts.iter();
401 let ctx = Self {
402 mint: next_account_info(account_iter)?,
403 token_account: next_account_info(account_iter)?,
404 owner: next_account_info(account_iter)?,
405 upstream_authority: next_account_info(account_iter)?,
406 delegate: next_account_info(account_iter)?,
407 freeze_authority: next_account_info(account_iter)?,
408 token_program: next_account_info(account_iter)?,
409 };
410 assert_with_msg(
411 ctx.mint.owner == &spl_token::id(),
412 ProgramError::IllegalOwner,
413 "Mint account must be owned by the Token Program",
414 )?;
415 assert_with_msg(
416 ctx.token_account.owner == ctx.token_program.key,
417 ProgramError::IllegalOwner,
418 "Token account must be owned by the Token Program",
419 )?;
420 assert_with_msg(
421 ctx.token_account.is_writable,
422 ProgramError::InvalidInstructionData,
423 "Token Account must be writable",
424 )?;
425 assert_with_msg(
426 ctx.token_program.key == &spl_token::id(),
427 ProgramError::InvalidInstructionData,
428 "Invalid key supplied for Token Program",
429 )?;
430 assert_with_msg(
431 ctx.upstream_authority.is_signer,
432 ProgramError::MissingRequiredSignature,
433 "Freeze authority must sign for modification",
434 )?;
435 assert_with_msg(
436 ctx.owner.is_signer,
437 ProgramError::MissingRequiredSignature,
438 "Owner must sign for modification",
439 )?;
440 Ok(ctx)
441 }
442}
443
444pub struct Revoke<'a, 'info> {
445 pub mint: &'a AccountInfo<'info>,
446 pub token_account: &'a AccountInfo<'info>,
447 pub owner: &'a AccountInfo<'info>,
448 pub upstream_authority: &'a AccountInfo<'info>,
449 pub freeze_authority: &'a AccountInfo<'info>,
450 pub token_program: &'a AccountInfo<'info>,
451}
452
453impl<'a, 'info> Revoke<'a, 'info> {
454 pub fn load(accounts: &'a [AccountInfo<'info>]) -> Result<Self, ProgramError> {
455 let account_iter = &mut accounts.iter();
456 let ctx = Self {
457 mint: next_account_info(account_iter)?,
458 token_account: next_account_info(account_iter)?,
459 owner: next_account_info(account_iter)?,
460 upstream_authority: next_account_info(account_iter)?,
461 freeze_authority: next_account_info(account_iter)?,
462 token_program: next_account_info(account_iter)?,
463 };
464 assert_with_msg(
465 ctx.mint.owner == &spl_token::id(),
466 ProgramError::IllegalOwner,
467 "Mint account must be owned by the Token Program",
468 )?;
469 assert_with_msg(
470 ctx.token_account.owner == ctx.token_program.key,
471 ProgramError::IllegalOwner,
472 "Token account must be owned by the Token Program",
473 )?;
474 assert_with_msg(
475 ctx.token_account.is_writable,
476 ProgramError::InvalidInstructionData,
477 "Token Account must be writable",
478 )?;
479 assert_with_msg(
480 ctx.token_program.key == &spl_token::id(),
481 ProgramError::InvalidInstructionData,
482 "Invalid key supplied for Token Program",
483 )?;
484 assert_with_msg(
485 ctx.upstream_authority.is_signer,
486 ProgramError::MissingRequiredSignature,
487 "Freeze authority must sign for modification",
488 )?;
489 assert_with_msg(
490 ctx.owner.is_signer,
491 ProgramError::MissingRequiredSignature,
492 "Owner must sign for modification",
493 )?;
494 Ok(ctx)
495 }
496}