spl_managed_token/
accounts.rs

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}