1use crate::*;
2use syn::parse::{Error as ParseError, Result as ParseResult};
3use syn::{bracketed, Token};
4
5pub fn parse(f: &syn::Field, f_ty: Option<&Ty>) -> ParseResult<ConstraintGroup> {
6 let mut constraints = ConstraintGroupBuilder::new(f_ty);
7 for attr in f.attrs.iter().filter(is_account) {
8 for c in attr.parse_args_with(Punctuated::<ConstraintToken, Comma>::parse_terminated)? {
9 constraints.add(c)?;
10 }
11 }
12 let account_constraints = constraints.build()?;
13
14 Ok(account_constraints)
15}
16
17pub fn is_account(attr: &&syn::Attribute) -> bool {
18 attr.path
19 .get_ident()
20 .is_some_and(|ident| ident == "account")
21}
22
23pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
25 let ident = stream.call(Ident::parse_any)?;
26 let kw = ident.to_string();
27
28 let c = match kw.as_str() {
29 "init" => ConstraintToken::Init(Context::new(
30 ident.span(),
31 ConstraintInit { if_needed: false },
32 )),
33 "init_if_needed" => ConstraintToken::Init(Context::new(
34 ident.span(),
35 ConstraintInit { if_needed: true },
36 )),
37 "zero" => ConstraintToken::Zeroed(Context::new(ident.span(), ConstraintZeroed {})),
38 "mut" => ConstraintToken::Mut(Context::new(
39 ident.span(),
40 ConstraintMut {
41 error: parse_optional_custom_error(&stream)?,
42 },
43 )),
44 "signer" => ConstraintToken::Signer(Context::new(
45 ident.span(),
46 ConstraintSigner {
47 error: parse_optional_custom_error(&stream)?,
48 },
49 )),
50 "executable" => {
51 ConstraintToken::Executable(Context::new(ident.span(), ConstraintExecutable {}))
52 }
53 "mint" => {
54 stream.parse::<Token![:]>()?;
55 stream.parse::<Token![:]>()?;
56 let kw = stream.call(Ident::parse_any)?.to_string();
57 stream.parse::<Token![=]>()?;
58
59 let span = ident
60 .span()
61 .join(stream.span())
62 .unwrap_or_else(|| ident.span());
63
64 match kw.as_str() {
65 "authority" => ConstraintToken::MintAuthority(Context::new(
66 span,
67 ConstraintMintAuthority {
68 mint_auth: stream.parse()?,
69 },
70 )),
71 "freeze_authority" => ConstraintToken::MintFreezeAuthority(Context::new(
72 span,
73 ConstraintMintFreezeAuthority {
74 mint_freeze_auth: stream.parse()?,
75 },
76 )),
77 "decimals" => ConstraintToken::MintDecimals(Context::new(
78 span,
79 ConstraintMintDecimals {
80 decimals: stream.parse()?,
81 },
82 )),
83 "token_program" => ConstraintToken::MintTokenProgram(Context::new(
84 span,
85 ConstraintTokenProgram {
86 token_program: stream.parse()?,
87 },
88 )),
89 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
90 }
91 }
92 "extensions" => {
93 stream.parse::<Token![:]>()?;
94 stream.parse::<Token![:]>()?;
95 let kw = stream.call(Ident::parse_any)?.to_string();
96
97 match kw.as_str() {
98 "group_pointer" => {
99 stream.parse::<Token![:]>()?;
100 stream.parse::<Token![:]>()?;
101 let kw = stream.call(Ident::parse_any)?.to_string();
102 stream.parse::<Token![=]>()?;
103
104 let span = ident
105 .span()
106 .join(stream.span())
107 .unwrap_or_else(|| ident.span());
108
109 match kw.as_str() {
110 "authority" => {
111 ConstraintToken::ExtensionGroupPointerAuthority(Context::new(
112 span,
113 ConstraintExtensionAuthority {
114 authority: stream.parse()?,
115 },
116 ))
117 }
118 "group_address" => {
119 ConstraintToken::ExtensionGroupPointerGroupAddress(Context::new(
120 span,
121 ConstraintExtensionGroupPointerGroupAddress {
122 group_address: stream.parse()?,
123 },
124 ))
125 }
126 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
127 }
128 }
129 "group_member_pointer" => {
130 stream.parse::<Token![:]>()?;
131 stream.parse::<Token![:]>()?;
132 let kw = stream.call(Ident::parse_any)?.to_string();
133 stream.parse::<Token![=]>()?;
134
135 let span = ident
136 .span()
137 .join(stream.span())
138 .unwrap_or_else(|| ident.span());
139
140 match kw.as_str() {
141 "authority" => {
142 ConstraintToken::ExtensionGroupMemberPointerAuthority(Context::new(
143 span,
144 ConstraintExtensionAuthority {
145 authority: stream.parse()?,
146 },
147 ))
148 }
149 "member_address" => {
150 ConstraintToken::ExtensionGroupMemberPointerMemberAddress(Context::new(
151 span,
152 ConstraintExtensionGroupMemberPointerMemberAddress {
153 member_address: stream.parse()?,
154 },
155 ))
156 }
157 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
158 }
159 }
160 "metadata_pointer" => {
161 stream.parse::<Token![:]>()?;
162 stream.parse::<Token![:]>()?;
163 let kw = stream.call(Ident::parse_any)?.to_string();
164 stream.parse::<Token![=]>()?;
165
166 let span = ident
167 .span()
168 .join(stream.span())
169 .unwrap_or_else(|| ident.span());
170
171 match kw.as_str() {
172 "authority" => {
173 ConstraintToken::ExtensionMetadataPointerAuthority(Context::new(
174 span,
175 ConstraintExtensionAuthority {
176 authority: stream.parse()?,
177 },
178 ))
179 }
180 "metadata_address" => {
181 ConstraintToken::ExtensionMetadataPointerMetadataAddress(Context::new(
182 span,
183 ConstraintExtensionMetadataPointerMetadataAddress {
184 metadata_address: stream.parse()?,
185 },
186 ))
187 }
188 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
189 }
190 }
191 "close_authority" => {
192 stream.parse::<Token![:]>()?;
193 stream.parse::<Token![:]>()?;
194 let kw = stream.call(Ident::parse_any)?.to_string();
195 stream.parse::<Token![=]>()?;
196
197 let span = ident
198 .span()
199 .join(stream.span())
200 .unwrap_or_else(|| ident.span());
201
202 match kw.as_str() {
203 "authority" => ConstraintToken::ExtensionCloseAuthority(Context::new(
204 span,
205 ConstraintExtensionAuthority {
206 authority: stream.parse()?,
207 },
208 )),
209 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
210 }
211 }
212 "permanent_delegate" => {
213 stream.parse::<Token![:]>()?;
214 stream.parse::<Token![:]>()?;
215 let kw = stream.call(Ident::parse_any)?.to_string();
216 stream.parse::<Token![=]>()?;
217
218 let span = ident
219 .span()
220 .join(stream.span())
221 .unwrap_or_else(|| ident.span());
222
223 match kw.as_str() {
224 "delegate" => ConstraintToken::ExtensionPermanentDelegate(Context::new(
225 span,
226 ConstraintExtensionPermanentDelegate {
227 permanent_delegate: stream.parse()?,
228 },
229 )),
230 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
231 }
232 }
233 "transfer_hook" => {
234 stream.parse::<Token![:]>()?;
235 stream.parse::<Token![:]>()?;
236 let kw = stream.call(Ident::parse_any)?.to_string();
237 stream.parse::<Token![=]>()?;
238
239 let span = ident
240 .span()
241 .join(stream.span())
242 .unwrap_or_else(|| ident.span());
243
244 match kw.as_str() {
245 "authority" => ConstraintToken::ExtensionTokenHookAuthority(Context::new(
246 span,
247 ConstraintExtensionAuthority {
248 authority: stream.parse()?,
249 },
250 )),
251 "program_id" => ConstraintToken::ExtensionTokenHookProgramId(Context::new(
252 span,
253 ConstraintExtensionTokenHookProgramId {
254 program_id: stream.parse()?,
255 },
256 )),
257 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
258 }
259 }
260 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
261 }
262 }
263 "token" => {
264 stream.parse::<Token![:]>()?;
265 stream.parse::<Token![:]>()?;
266 let kw = stream.call(Ident::parse_any)?.to_string();
267 stream.parse::<Token![=]>()?;
268
269 let span = ident
270 .span()
271 .join(stream.span())
272 .unwrap_or_else(|| ident.span());
273
274 match kw.as_str() {
275 "mint" => ConstraintToken::TokenMint(Context::new(
276 span,
277 ConstraintTokenMint {
278 mint: stream.parse()?,
279 },
280 )),
281 "authority" => ConstraintToken::TokenAuthority(Context::new(
282 span,
283 ConstraintTokenAuthority {
284 auth: stream.parse()?,
285 },
286 )),
287 "token_program" => ConstraintToken::TokenTokenProgram(Context::new(
288 span,
289 ConstraintTokenProgram {
290 token_program: stream.parse()?,
291 },
292 )),
293 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
294 }
295 }
296 "associated_token" => {
297 stream.parse::<Token![:]>()?;
298 stream.parse::<Token![:]>()?;
299 let kw = stream.call(Ident::parse_any)?.to_string();
300 stream.parse::<Token![=]>()?;
301
302 let span = ident
303 .span()
304 .join(stream.span())
305 .unwrap_or_else(|| ident.span());
306
307 match kw.as_str() {
308 "mint" => ConstraintToken::AssociatedTokenMint(Context::new(
309 span,
310 ConstraintTokenMint {
311 mint: stream.parse()?,
312 },
313 )),
314 "authority" => ConstraintToken::AssociatedTokenAuthority(Context::new(
315 span,
316 ConstraintTokenAuthority {
317 auth: stream.parse()?,
318 },
319 )),
320 "token_program" => ConstraintToken::AssociatedTokenTokenProgram(Context::new(
321 span,
322 ConstraintTokenProgram {
323 token_program: stream.parse()?,
324 },
325 )),
326 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
327 }
328 }
329 "bump" => {
330 let bump = {
331 if stream.peek(Token![=]) {
332 stream.parse::<Token![=]>()?;
333 Some(stream.parse()?)
334 } else {
335 None
336 }
337 };
338 ConstraintToken::Bump(Context::new(ident.span(), ConstraintTokenBump { bump }))
339 }
340 "seeds" => {
341 if stream.peek(Token![:]) {
342 stream.parse::<Token![:]>()?;
343 stream.parse::<Token![:]>()?;
344 let kw = stream.call(Ident::parse_any)?.to_string();
345 stream.parse::<Token![=]>()?;
346
347 let span = ident
348 .span()
349 .join(stream.span())
350 .unwrap_or_else(|| ident.span());
351
352 match kw.as_str() {
353 "program" => ConstraintToken::ProgramSeed(Context::new(
354 span,
355 ConstraintProgramSeed {
356 program_seed: stream.parse()?,
357 },
358 )),
359 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
360 }
361 } else {
362 stream.parse::<Token![=]>()?;
363 let span = ident
364 .span()
365 .join(stream.span())
366 .unwrap_or_else(|| ident.span());
367 let seeds;
368 let bracket = bracketed!(seeds in stream);
369 ConstraintToken::Seeds(Context::new(
370 span.join(bracket.span).unwrap_or(span),
371 ConstraintSeeds {
372 seeds: seeds.parse_terminated(Expr::parse)?,
373 },
374 ))
375 }
376 }
377 "realloc" => {
378 if stream.peek(Token![=]) {
379 stream.parse::<Token![=]>()?;
380 let span = ident
381 .span()
382 .join(stream.span())
383 .unwrap_or_else(|| ident.span());
384 ConstraintToken::Realloc(Context::new(
385 span,
386 ConstraintRealloc {
387 space: stream.parse()?,
388 },
389 ))
390 } else {
391 stream.parse::<Token![:]>()?;
392 stream.parse::<Token![:]>()?;
393 let kw = stream.call(Ident::parse_any)?.to_string();
394 stream.parse::<Token![=]>()?;
395
396 let span = ident
397 .span()
398 .join(stream.span())
399 .unwrap_or_else(|| ident.span());
400
401 match kw.as_str() {
402 "payer" => ConstraintToken::ReallocPayer(Context::new(
403 span,
404 ConstraintReallocPayer {
405 target: stream.parse()?,
406 },
407 )),
408 "zero" => ConstraintToken::ReallocZero(Context::new(
409 span,
410 ConstraintReallocZero {
411 zero: stream.parse()?,
412 },
413 )),
414 _ => return Err(ParseError::new(ident.span(), "Invalid attribute. realloc::payer and realloc::zero are the only valid attributes")),
415 }
416 }
417 }
418 _ => {
419 stream.parse::<Token![=]>()?;
420 let span = ident
421 .span()
422 .join(stream.span())
423 .unwrap_or_else(|| ident.span());
424 match kw.as_str() {
425 "has_one" => ConstraintToken::HasOne(Context::new(
426 span,
427 ConstraintHasOne {
428 join_target: stream.parse()?,
429 error: parse_optional_custom_error(&stream)?,
430 },
431 )),
432 "owner" => ConstraintToken::Owner(Context::new(
433 span,
434 ConstraintOwner {
435 owner_address: stream.parse()?,
436 error: parse_optional_custom_error(&stream)?,
437 },
438 )),
439 "rent_exempt" => ConstraintToken::RentExempt(Context::new(
440 span,
441 match stream.parse::<Ident>()?.to_string().as_str() {
442 "skip" => ConstraintRentExempt::Skip,
443 "enforce" => ConstraintRentExempt::Enforce,
444 _ => {
445 return Err(ParseError::new(
446 span,
447 "rent_exempt must be either skip or enforce",
448 ))
449 }
450 },
451 )),
452 "payer" => ConstraintToken::Payer(Context::new(
453 span,
454 ConstraintPayer {
455 target: stream.parse()?,
456 },
457 )),
458 "space" => ConstraintToken::Space(Context::new(
459 span,
460 ConstraintSpace {
461 space: stream.parse()?,
462 },
463 )),
464 "constraint" => ConstraintToken::Raw(Context::new(
465 span,
466 ConstraintRaw {
467 raw: stream.parse()?,
468 error: parse_optional_custom_error(&stream)?,
469 },
470 )),
471 "close" => ConstraintToken::Close(Context::new(
472 span,
473 ConstraintClose {
474 sol_dest: stream.parse()?,
475 },
476 )),
477 "address" => ConstraintToken::Address(Context::new(
478 span,
479 ConstraintAddress {
480 address: stream.parse()?,
481 error: parse_optional_custom_error(&stream)?,
482 },
483 )),
484 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
485 }
486 }
487 };
488
489 Ok(c)
490}
491
492fn parse_optional_custom_error(stream: &ParseStream) -> ParseResult<Option<Expr>> {
493 if stream.peek(Token![@]) {
494 stream.parse::<Token![@]>()?;
495 stream.parse().map(Some)
496 } else {
497 Ok(None)
498 }
499}
500
501#[derive(Default)]
502pub struct ConstraintGroupBuilder<'ty> {
503 pub f_ty: Option<&'ty Ty>,
504 pub init: Option<Context<ConstraintInit>>,
505 pub zeroed: Option<Context<ConstraintZeroed>>,
506 pub mutable: Option<Context<ConstraintMut>>,
507 pub signer: Option<Context<ConstraintSigner>>,
508 pub has_one: Vec<Context<ConstraintHasOne>>,
509 pub raw: Vec<Context<ConstraintRaw>>,
510 pub owner: Option<Context<ConstraintOwner>>,
511 pub rent_exempt: Option<Context<ConstraintRentExempt>>,
512 pub seeds: Option<Context<ConstraintSeeds>>,
513 pub executable: Option<Context<ConstraintExecutable>>,
514 pub payer: Option<Context<ConstraintPayer>>,
515 pub space: Option<Context<ConstraintSpace>>,
516 pub close: Option<Context<ConstraintClose>>,
517 pub address: Option<Context<ConstraintAddress>>,
518 pub token_mint: Option<Context<ConstraintTokenMint>>,
519 pub token_authority: Option<Context<ConstraintTokenAuthority>>,
520 pub token_token_program: Option<Context<ConstraintTokenProgram>>,
521 pub associated_token_mint: Option<Context<ConstraintTokenMint>>,
522 pub associated_token_authority: Option<Context<ConstraintTokenAuthority>>,
523 pub associated_token_token_program: Option<Context<ConstraintTokenProgram>>,
524 pub mint_authority: Option<Context<ConstraintMintAuthority>>,
525 pub mint_freeze_authority: Option<Context<ConstraintMintFreezeAuthority>>,
526 pub mint_decimals: Option<Context<ConstraintMintDecimals>>,
527 pub mint_token_program: Option<Context<ConstraintTokenProgram>>,
528 pub extension_group_pointer_authority: Option<Context<ConstraintExtensionAuthority>>,
529 pub extension_group_pointer_group_address:
530 Option<Context<ConstraintExtensionGroupPointerGroupAddress>>,
531 pub extension_group_member_pointer_authority: Option<Context<ConstraintExtensionAuthority>>,
532 pub extension_group_member_pointer_member_address:
533 Option<Context<ConstraintExtensionGroupMemberPointerMemberAddress>>,
534 pub extension_metadata_pointer_authority: Option<Context<ConstraintExtensionAuthority>>,
535 pub extension_metadata_pointer_metadata_address:
536 Option<Context<ConstraintExtensionMetadataPointerMetadataAddress>>,
537 pub extension_close_authority: Option<Context<ConstraintExtensionAuthority>>,
538 pub extension_transfer_hook_authority: Option<Context<ConstraintExtensionAuthority>>,
539 pub extension_transfer_hook_program_id: Option<Context<ConstraintExtensionTokenHookProgramId>>,
540 pub extension_permanent_delegate: Option<Context<ConstraintExtensionPermanentDelegate>>,
541 pub bump: Option<Context<ConstraintTokenBump>>,
542 pub program_seed: Option<Context<ConstraintProgramSeed>>,
543 pub realloc: Option<Context<ConstraintRealloc>>,
544 pub realloc_payer: Option<Context<ConstraintReallocPayer>>,
545 pub realloc_zero: Option<Context<ConstraintReallocZero>>,
546}
547
548impl<'ty> ConstraintGroupBuilder<'ty> {
549 pub fn new(f_ty: Option<&'ty Ty>) -> Self {
550 Self {
551 f_ty,
552 init: None,
553 zeroed: None,
554 mutable: None,
555 signer: None,
556 has_one: Vec::new(),
557 raw: Vec::new(),
558 owner: None,
559 rent_exempt: None,
560 seeds: None,
561 executable: None,
562 payer: None,
563 space: None,
564 close: None,
565 address: None,
566 token_mint: None,
567 token_authority: None,
568 token_token_program: None,
569 associated_token_mint: None,
570 associated_token_authority: None,
571 associated_token_token_program: None,
572 mint_authority: None,
573 mint_freeze_authority: None,
574 mint_decimals: None,
575 mint_token_program: None,
576 extension_group_pointer_authority: None,
577 extension_group_pointer_group_address: None,
578 extension_group_member_pointer_authority: None,
579 extension_group_member_pointer_member_address: None,
580 extension_metadata_pointer_authority: None,
581 extension_metadata_pointer_metadata_address: None,
582 extension_close_authority: None,
583 extension_transfer_hook_authority: None,
584 extension_transfer_hook_program_id: None,
585 extension_permanent_delegate: None,
586 bump: None,
587 program_seed: None,
588 realloc: None,
589 realloc_payer: None,
590 realloc_zero: None,
591 }
592 }
593
594 pub fn build(mut self) -> ParseResult<ConstraintGroup> {
595 if let Some(i) = &self.init {
597 if cfg!(not(feature = "init-if-needed")) && i.if_needed {
598 return Err(ParseError::new(
599 i.span(),
600 "init_if_needed requires that anchor-lang be imported \
601 with the init-if-needed cargo feature enabled. \
602 Carefully read the init_if_needed docs before using this feature \
603 to make sure you know how to protect yourself against \
604 re-initialization attacks.",
605 ));
606 }
607
608 match self.mutable {
609 Some(m) => {
610 return Err(ParseError::new(
611 m.span(),
612 "mut cannot be provided with init",
613 ))
614 }
615 None => self
616 .mutable
617 .replace(Context::new(i.span(), ConstraintMut { error: None })),
618 };
619 if self.rent_exempt.is_none() {
621 self.rent_exempt
622 .replace(Context::new(i.span(), ConstraintRentExempt::Enforce));
623 }
624 if self.payer.is_none() {
625 return Err(ParseError::new(
626 i.span(),
627 "payer must be provided when initializing an account",
628 ));
629 }
630 if self.signer.is_none() && self.seeds.is_none() && self.associated_token_mint.is_none()
634 {
635 self.signer
636 .replace(Context::new(i.span(), ConstraintSigner { error: None }));
637 }
638
639 if let Some(b) = &self.bump {
641 if b.bump.is_some() {
642 return Err(ParseError::new(
643 b.span(),
644 "bump targets should not be provided with init. Please use bump without a target."
645 ));
646 }
647 }
648
649 if let Some(token_mint) = &self.token_mint {
651 if self.token_authority.is_none() {
652 return Err(ParseError::new(
653 token_mint.span(),
654 "when initializing, token authority must be provided if token mint is",
655 ));
656 }
657 }
658 if let Some(token_authority) = &self.token_authority {
659 if self.token_mint.is_none() {
660 return Err(ParseError::new(
661 token_authority.span(),
662 "when initializing, token mint must be provided if token authority is",
663 ));
664 }
665 }
666
667 if let Some(mint_decimals) = &self.mint_decimals {
669 if self.mint_authority.is_none() {
670 return Err(ParseError::new(
671 mint_decimals.span(),
672 "when initializing, mint authority must be provided if mint decimals is",
673 ));
674 }
675 }
676 if let Some(mint_authority) = &self.mint_authority {
677 if self.mint_decimals.is_none() {
678 return Err(ParseError::new(
679 mint_authority.span(),
680 "when initializing, mint decimals must be provided if mint authority is",
681 ));
682 }
683 }
684 }
685
686 if let Some(r) = &self.realloc {
688 if self.realloc_payer.is_none() {
689 return Err(ParseError::new(
690 r.span(),
691 "realloc::payer must be provided when using realloc",
692 ));
693 }
694 if self.realloc_zero.is_none() {
695 return Err(ParseError::new(
696 r.span(),
697 "realloc::zero must be provided when using realloc",
698 ));
699 }
700 }
701
702 if let Some(z) = &self.zeroed {
704 match self.mutable {
705 Some(m) => {
706 return Err(ParseError::new(
707 m.span(),
708 "mut cannot be provided with zeroed",
709 ))
710 }
711 None => self
712 .mutable
713 .replace(Context::new(z.span(), ConstraintMut { error: None })),
714 };
715 if self.rent_exempt.is_none() {
717 self.rent_exempt
718 .replace(Context::new(z.span(), ConstraintRentExempt::Enforce));
719 }
720 }
721
722 if let Some(i) = &self.seeds {
724 if self.init.is_some() && self.payer.is_none() {
725 return Err(ParseError::new(
726 i.span(),
727 "payer must be provided when creating a program derived address",
728 ));
729 }
730 if self.bump.is_none() {
731 return Err(ParseError::new(
732 i.span(),
733 "bump must be provided with seeds",
734 ));
735 }
736 }
737
738 if let Some(i) = &self.init {
740 let initializing_token_program_acc = self.token_mint.is_some()
741 || self.mint_authority.is_some()
742 || self.token_authority.is_some()
743 || self.associated_token_authority.is_some();
744
745 match (self.space.is_some(), initializing_token_program_acc) {
746 (true, true) => {
747 return Err(ParseError::new(
748 self.space.as_ref().unwrap().span(),
749 "space is not required for initializing an spl account",
750 ));
751 }
752 (false, false) => {
753 return Err(ParseError::new(
754 i.span(),
755 "space must be provided with init",
756 ));
757 }
758 _ => (),
759 }
760 }
761
762 let ConstraintGroupBuilder {
763 f_ty: _,
764 init,
765 zeroed,
766 mutable,
767 signer,
768 has_one,
769 raw,
770 owner,
771 rent_exempt,
772 seeds,
773 executable,
774 payer,
775 space,
776 close,
777 address,
778 token_mint,
779 token_authority,
780 token_token_program,
781 associated_token_mint,
782 associated_token_authority,
783 associated_token_token_program,
784 mint_authority,
785 mint_freeze_authority,
786 mint_decimals,
787 mint_token_program,
788 extension_group_pointer_authority,
789 extension_group_pointer_group_address,
790 extension_group_member_pointer_authority,
791 extension_group_member_pointer_member_address,
792 extension_metadata_pointer_authority,
793 extension_metadata_pointer_metadata_address,
794 extension_close_authority,
795 extension_transfer_hook_authority,
796 extension_transfer_hook_program_id,
797 extension_permanent_delegate,
798 bump,
799 program_seed,
800 realloc,
801 realloc_payer,
802 realloc_zero,
803 } = self;
804
805 macro_rules! into_inner {
807 ($opt:ident) => {
808 $opt.map(|c| c.into_inner())
809 };
810 ($opt:expr) => {
811 $opt.map(|c| c.into_inner())
812 };
813 }
814 macro_rules! into_inner_vec {
816 ($opt:ident) => {
817 $opt.into_iter().map(|c| c.into_inner()).collect()
818 };
819 }
820
821 let is_init = init.is_some();
822 let seeds = seeds.map(|c| ConstraintSeedsGroup {
823 is_init,
824 seeds: c.seeds.clone(),
825 bump: into_inner!(bump)
826 .map(|b| b.bump)
827 .expect("bump must be provided with seeds"),
828 program_seed: into_inner!(program_seed).map(|id| id.program_seed),
829 });
830 let associated_token = match (
831 associated_token_mint,
832 associated_token_authority,
833 &associated_token_token_program,
834 ) {
835 (Some(mint), Some(auth), _) => Some(ConstraintAssociatedToken {
836 wallet: auth.into_inner().auth,
837 mint: mint.into_inner().mint,
838 token_program: associated_token_token_program
839 .as_ref()
840 .map(|a| a.clone().into_inner().token_program),
841 }),
842 (Some(mint), None, _) => return Err(ParseError::new(
843 mint.span(),
844 "authority must be provided to specify an associated token program derived address",
845 )),
846 (None, Some(auth), _) => {
847 return Err(ParseError::new(
848 auth.span(),
849 "mint must be provided to specify an associated token program derived address",
850 ))
851 },
852 (None, None, Some(token_program)) => {
853 return Err(ParseError::new(
854 token_program.span(),
855 "mint and authority must be provided to specify an associated token program derived address",
856 ))
857 }
858 _ => None,
859 };
860 if let Some(associated_token) = &associated_token {
861 if seeds.is_some() {
862 return Err(ParseError::new(
863 associated_token.mint.span(),
864 "'associated_token' constraints cannot be used with the 'seeds' constraint",
865 ));
866 }
867 }
868
869 let token_account = match (&token_mint, &token_authority, &token_token_program) {
870 (None, None, None) => None,
871 _ => Some(ConstraintTokenAccountGroup {
872 mint: token_mint.as_ref().map(|a| a.clone().into_inner().mint),
873 authority: token_authority
874 .as_ref()
875 .map(|a| a.clone().into_inner().auth),
876 token_program: token_token_program
877 .as_ref()
878 .map(|a| a.clone().into_inner().token_program),
879 }),
880 };
881
882 let mint = match (
883 &mint_decimals,
884 &mint_authority,
885 &mint_freeze_authority,
886 &mint_token_program,
887 &extension_group_pointer_authority,
888 &extension_group_pointer_group_address,
889 &extension_group_member_pointer_authority,
890 &extension_group_member_pointer_member_address,
891 &extension_metadata_pointer_authority,
892 &extension_metadata_pointer_metadata_address,
893 &extension_close_authority,
894 &extension_transfer_hook_authority,
895 &extension_transfer_hook_program_id,
896 &extension_permanent_delegate,
897 ) {
898 (
899 None,
900 None,
901 None,
902 None,
903 None,
904 None,
905 None,
906 None,
907 None,
908 None,
909 None,
910 None,
911 None,
912 None,
913 ) => None,
914 _ => Some(ConstraintTokenMintGroup {
915 decimals: mint_decimals
916 .as_ref()
917 .map(|a| a.clone().into_inner().decimals),
918 mint_authority: mint_authority
919 .as_ref()
920 .map(|a| a.clone().into_inner().mint_auth),
921 freeze_authority: mint_freeze_authority
922 .as_ref()
923 .map(|a| a.clone().into_inner().mint_freeze_auth),
924 token_program: mint_token_program
925 .as_ref()
926 .map(|a| a.clone().into_inner().token_program),
927 group_pointer_authority: extension_group_pointer_authority
929 .as_ref()
930 .map(|a| a.clone().into_inner().authority),
931 group_pointer_group_address: extension_group_pointer_group_address
932 .as_ref()
933 .map(|a| a.clone().into_inner().group_address),
934 group_member_pointer_authority: extension_group_member_pointer_authority
935 .as_ref()
936 .map(|a| a.clone().into_inner().authority),
937 group_member_pointer_member_address: extension_group_member_pointer_member_address
938 .as_ref()
939 .map(|a| a.clone().into_inner().member_address),
940 metadata_pointer_authority: extension_metadata_pointer_authority
941 .as_ref()
942 .map(|a| a.clone().into_inner().authority),
943 metadata_pointer_metadata_address: extension_metadata_pointer_metadata_address
944 .as_ref()
945 .map(|a| a.clone().into_inner().metadata_address),
946 close_authority: extension_close_authority
947 .as_ref()
948 .map(|a| a.clone().into_inner().authority),
949 permanent_delegate: extension_permanent_delegate
950 .as_ref()
951 .map(|a| a.clone().into_inner().permanent_delegate),
952 transfer_hook_authority: extension_transfer_hook_authority
953 .as_ref()
954 .map(|a| a.clone().into_inner().authority),
955 transfer_hook_program_id: extension_transfer_hook_program_id
956 .as_ref()
957 .map(|a| a.clone().into_inner().program_id),
958 }),
959 };
960
961 Ok(ConstraintGroup {
962 init: init.as_ref().map(|i| Ok(ConstraintInitGroup {
963 if_needed: i.if_needed,
964 seeds: seeds.clone(),
965 payer: into_inner!(payer.clone()).unwrap().target,
966 space: space.clone().map(|s| s.space.clone()),
967 kind: if let Some(tm) = &token_mint {
968 InitKind::Token {
969 mint: tm.clone().into_inner().mint,
970 owner: match &token_authority {
971 Some(a) => a.clone().into_inner().auth,
972 None => return Err(ParseError::new(
973 tm.span(),
974 "authority must be provided to initialize a token program derived address"
975 )),
976 },
977 token_program: token_token_program.map(|tp| tp.into_inner().token_program),
978 }
979 } else if let Some(at) = &associated_token {
980 InitKind::AssociatedToken {
981 mint: at.mint.clone(),
982 owner: at.wallet.clone(),
983 token_program: associated_token_token_program.map(|tp| tp.into_inner().token_program),
984 }
985 } else if let Some(d) = &mint_decimals {
986 InitKind::Mint {
987 decimals: d.clone().into_inner().decimals,
988 owner: match &mint_authority {
989 Some(a) => a.clone().into_inner().mint_auth,
990 None => return Err(ParseError::new(
991 d.span(),
992 "authority must be provided to initialize a mint program derived address"
993 ))
994 },
995 freeze_authority: mint_freeze_authority.map(|fa| fa.into_inner().mint_freeze_auth),
996 token_program: mint_token_program.map(|tp| tp.into_inner().token_program),
997 group_pointer_authority: extension_group_pointer_authority.map(|gpa| gpa.into_inner().authority),
999 group_pointer_group_address: extension_group_pointer_group_address.map(|gpga| gpga.into_inner().group_address),
1000 group_member_pointer_authority: extension_group_member_pointer_authority.map(|gmpa| gmpa.into_inner().authority),
1001 group_member_pointer_member_address: extension_group_member_pointer_member_address.map(|gmpma| gmpma.into_inner().member_address),
1002 metadata_pointer_authority: extension_metadata_pointer_authority.map(|mpa| mpa.into_inner().authority),
1003 metadata_pointer_metadata_address: extension_metadata_pointer_metadata_address.map(|mpma| mpma.into_inner().metadata_address),
1004 close_authority: extension_close_authority.map(|ca| ca.into_inner().authority),
1005 permanent_delegate: extension_permanent_delegate.map(|pd| pd.into_inner().permanent_delegate),
1006 transfer_hook_authority: extension_transfer_hook_authority.map(|tha| tha.into_inner().authority),
1007 transfer_hook_program_id: extension_transfer_hook_program_id.map(|thpid| thpid.into_inner().program_id),
1008 }
1009 } else {
1010 InitKind::Program {
1011 owner: owner.as_ref().map(|o| o.owner_address.clone()),
1012 }
1013 },
1014 })).transpose()?,
1015 realloc: realloc.as_ref().map(|r| ConstraintReallocGroup {
1016 payer: into_inner!(realloc_payer).unwrap().target,
1017 space: r.space.clone(),
1018 zero: into_inner!(realloc_zero).unwrap().zero,
1019 }),
1020 zeroed: into_inner!(zeroed),
1021 mutable: into_inner!(mutable),
1022 signer: into_inner!(signer),
1023 has_one: into_inner_vec!(has_one),
1024 raw: into_inner_vec!(raw),
1025 owner: into_inner!(owner),
1026 rent_exempt: into_inner!(rent_exempt),
1027 executable: into_inner!(executable),
1028 close: into_inner!(close),
1029 address: into_inner!(address),
1030 associated_token: if !is_init { associated_token } else { None },
1031 seeds,
1032 token_account: if !is_init {token_account} else {None},
1033 mint: if !is_init {mint} else {None},
1034 })
1035 }
1036
1037 pub fn add(&mut self, c: ConstraintToken) -> ParseResult<()> {
1038 match c {
1039 ConstraintToken::Init(c) => self.add_init(c),
1040 ConstraintToken::Zeroed(c) => self.add_zeroed(c),
1041 ConstraintToken::Mut(c) => self.add_mut(c),
1042 ConstraintToken::Signer(c) => self.add_signer(c),
1043 ConstraintToken::HasOne(c) => self.add_has_one(c),
1044 ConstraintToken::Raw(c) => self.add_raw(c),
1045 ConstraintToken::Owner(c) => self.add_owner(c),
1046 ConstraintToken::RentExempt(c) => self.add_rent_exempt(c),
1047 ConstraintToken::Seeds(c) => self.add_seeds(c),
1048 ConstraintToken::Executable(c) => self.add_executable(c),
1049 ConstraintToken::Payer(c) => self.add_payer(c),
1050 ConstraintToken::Space(c) => self.add_space(c),
1051 ConstraintToken::Close(c) => self.add_close(c),
1052 ConstraintToken::Address(c) => self.add_address(c),
1053 ConstraintToken::TokenAuthority(c) => self.add_token_authority(c),
1054 ConstraintToken::TokenMint(c) => self.add_token_mint(c),
1055 ConstraintToken::TokenTokenProgram(c) => self.add_token_token_program(c),
1056 ConstraintToken::AssociatedTokenAuthority(c) => self.add_associated_token_authority(c),
1057 ConstraintToken::AssociatedTokenMint(c) => self.add_associated_token_mint(c),
1058 ConstraintToken::AssociatedTokenTokenProgram(c) => {
1059 self.add_associated_token_token_program(c)
1060 }
1061 ConstraintToken::MintAuthority(c) => self.add_mint_authority(c),
1062 ConstraintToken::MintFreezeAuthority(c) => self.add_mint_freeze_authority(c),
1063 ConstraintToken::MintDecimals(c) => self.add_mint_decimals(c),
1064 ConstraintToken::MintTokenProgram(c) => self.add_mint_token_program(c),
1065 ConstraintToken::Bump(c) => self.add_bump(c),
1066 ConstraintToken::ProgramSeed(c) => self.add_program_seed(c),
1067 ConstraintToken::Realloc(c) => self.add_realloc(c),
1068 ConstraintToken::ReallocPayer(c) => self.add_realloc_payer(c),
1069 ConstraintToken::ReallocZero(c) => self.add_realloc_zero(c),
1070 ConstraintToken::ExtensionGroupPointerAuthority(c) => {
1071 self.add_extension_group_pointer_authority(c)
1072 }
1073 ConstraintToken::ExtensionGroupPointerGroupAddress(c) => {
1074 self.add_extension_group_pointer_group_address(c)
1075 }
1076 ConstraintToken::ExtensionGroupMemberPointerAuthority(c) => {
1077 self.add_extension_group_member_pointer_authority(c)
1078 }
1079 ConstraintToken::ExtensionGroupMemberPointerMemberAddress(c) => {
1080 self.add_extension_group_member_pointer_member_address(c)
1081 }
1082 ConstraintToken::ExtensionMetadataPointerAuthority(c) => {
1083 self.add_extension_metadata_pointer_authority(c)
1084 }
1085 ConstraintToken::ExtensionMetadataPointerMetadataAddress(c) => {
1086 self.add_extension_metadata_pointer_metadata_address(c)
1087 }
1088 ConstraintToken::ExtensionCloseAuthority(c) => self.add_extension_close_authority(c),
1089 ConstraintToken::ExtensionTokenHookAuthority(c) => self.add_extension_authority(c),
1090 ConstraintToken::ExtensionTokenHookProgramId(c) => {
1091 self.add_extension_transfer_hook_program_id(c)
1092 }
1093 ConstraintToken::ExtensionPermanentDelegate(c) => {
1094 self.add_extension_permanent_delegate(c)
1095 }
1096 }
1097 }
1098
1099 fn add_init(&mut self, c: Context<ConstraintInit>) -> ParseResult<()> {
1100 if self.init.is_some() {
1101 return Err(ParseError::new(c.span(), "init already provided"));
1102 }
1103 if self.zeroed.is_some() {
1104 return Err(ParseError::new(c.span(), "zeroed already provided"));
1105 }
1106 if self.token_mint.is_some() {
1107 return Err(ParseError::new(
1108 c.span(),
1109 "init must be provided before token mint",
1110 ));
1111 }
1112 if self.token_authority.is_some() {
1113 return Err(ParseError::new(
1114 c.span(),
1115 "init must be provided before token authority",
1116 ));
1117 }
1118 if self.token_token_program.is_some() {
1119 return Err(ParseError::new(
1120 c.span(),
1121 "init must be provided before token account token program",
1122 ));
1123 }
1124 if self.mint_authority.is_some() {
1125 return Err(ParseError::new(
1126 c.span(),
1127 "init must be provided before mint authority",
1128 ));
1129 }
1130 if self.mint_freeze_authority.is_some() {
1131 return Err(ParseError::new(
1132 c.span(),
1133 "init must be provided before mint freeze authority",
1134 ));
1135 }
1136 if self.mint_decimals.is_some() {
1137 return Err(ParseError::new(
1138 c.span(),
1139 "init must be provided before mint decimals",
1140 ));
1141 }
1142 if self.mint_token_program.is_some() {
1143 return Err(ParseError::new(
1144 c.span(),
1145 "init must be provided before mint token program",
1146 ));
1147 }
1148 if self.associated_token_mint.is_some() {
1149 return Err(ParseError::new(
1150 c.span(),
1151 "init must be provided before associated token mint",
1152 ));
1153 }
1154 if self.associated_token_authority.is_some() {
1155 return Err(ParseError::new(
1156 c.span(),
1157 "init must be provided before associated token authority",
1158 ));
1159 }
1160 if self.associated_token_token_program.is_some() {
1161 return Err(ParseError::new(
1162 c.span(),
1163 "init must be provided before associated token account token program",
1164 ));
1165 }
1166 self.init.replace(c);
1167 Ok(())
1168 }
1169
1170 fn add_zeroed(&mut self, c: Context<ConstraintZeroed>) -> ParseResult<()> {
1171 if self.zeroed.is_some() {
1172 return Err(ParseError::new(c.span(), "zeroed already provided"));
1173 }
1174 if self.init.is_some() {
1175 return Err(ParseError::new(c.span(), "init already provided"));
1176 }
1177
1178 if !matches!(
1181 &self.f_ty,
1182 Some(Ty::Account(_) | Ty::LazyAccount(_) | Ty::AccountLoader(_))
1183 ) {
1184 return Err(ParseError::new(
1185 c.span(),
1186 "`zero` constraint requires the type to implement the `Discriminator` trait",
1187 ));
1188 }
1189 self.zeroed.replace(c);
1190 Ok(())
1191 }
1192
1193 fn add_realloc(&mut self, c: Context<ConstraintRealloc>) -> ParseResult<()> {
1194 if !matches!(self.f_ty, Some(Ty::Account(_)))
1195 && !matches!(self.f_ty, Some(Ty::LazyAccount(_)))
1196 && !matches!(self.f_ty, Some(Ty::AccountLoader(_)))
1197 {
1198 return Err(ParseError::new(
1199 c.span(),
1200 "realloc must be on an Account, LazyAccount or AccountLoader",
1201 ));
1202 }
1203 if self.mutable.is_none() {
1204 return Err(ParseError::new(
1205 c.span(),
1206 "mut must be provided before realloc",
1207 ));
1208 }
1209 if self.realloc.is_some() {
1210 return Err(ParseError::new(c.span(), "realloc already provided"));
1211 }
1212 self.realloc.replace(c);
1213 Ok(())
1214 }
1215
1216 fn add_realloc_payer(&mut self, c: Context<ConstraintReallocPayer>) -> ParseResult<()> {
1217 if self.realloc.is_none() {
1218 return Err(ParseError::new(
1219 c.span(),
1220 "realloc must be provided before realloc::payer",
1221 ));
1222 }
1223 if self.realloc_payer.is_some() {
1224 return Err(ParseError::new(c.span(), "realloc::payer already provided"));
1225 }
1226 self.realloc_payer.replace(c);
1227 Ok(())
1228 }
1229
1230 fn add_realloc_zero(&mut self, c: Context<ConstraintReallocZero>) -> ParseResult<()> {
1231 if self.realloc.is_none() {
1232 return Err(ParseError::new(
1233 c.span(),
1234 "realloc must be provided before realloc::zero",
1235 ));
1236 }
1237 if self.realloc_zero.is_some() {
1238 return Err(ParseError::new(c.span(), "realloc::zero already provided"));
1239 }
1240 self.realloc_zero.replace(c);
1241 Ok(())
1242 }
1243
1244 fn add_close(&mut self, c: Context<ConstraintClose>) -> ParseResult<()> {
1245 if !matches!(self.f_ty, Some(Ty::Account(_)))
1246 && !matches!(self.f_ty, Some(Ty::LazyAccount(_)))
1247 && !matches!(self.f_ty, Some(Ty::AccountLoader(_)))
1248 {
1249 return Err(ParseError::new(
1250 c.span(),
1251 "close must be on an Account, LazyAccount or AccountLoader",
1252 ));
1253 }
1254 if self.mutable.is_none() {
1255 return Err(ParseError::new(
1256 c.span(),
1257 "mut must be provided before close",
1258 ));
1259 }
1260 if self.close.is_some() {
1261 return Err(ParseError::new(c.span(), "close already provided"));
1262 }
1263 self.close.replace(c);
1264 Ok(())
1265 }
1266
1267 fn add_address(&mut self, c: Context<ConstraintAddress>) -> ParseResult<()> {
1268 if self.address.is_some() {
1269 return Err(ParseError::new(c.span(), "address already provided"));
1270 }
1271 self.address.replace(c);
1272 Ok(())
1273 }
1274
1275 fn add_token_mint(&mut self, c: Context<ConstraintTokenMint>) -> ParseResult<()> {
1276 if self.token_mint.is_some() {
1277 return Err(ParseError::new(c.span(), "token mint already provided"));
1278 }
1279 if self.associated_token_mint.is_some() {
1280 return Err(ParseError::new(
1281 c.span(),
1282 "associated token mint already provided",
1283 ));
1284 }
1285 self.token_mint.replace(c);
1286 Ok(())
1287 }
1288
1289 fn add_associated_token_mint(&mut self, c: Context<ConstraintTokenMint>) -> ParseResult<()> {
1290 if self.associated_token_mint.is_some() {
1291 return Err(ParseError::new(
1292 c.span(),
1293 "associated token mint already provided",
1294 ));
1295 }
1296 if self.token_mint.is_some() {
1297 return Err(ParseError::new(c.span(), "token mint already provided"));
1298 }
1299 self.associated_token_mint.replace(c);
1300 Ok(())
1301 }
1302
1303 fn add_bump(&mut self, c: Context<ConstraintTokenBump>) -> ParseResult<()> {
1304 if self.bump.is_some() {
1305 return Err(ParseError::new(c.span(), "bump already provided"));
1306 }
1307 if self.seeds.is_none() {
1308 return Err(ParseError::new(
1309 c.span(),
1310 "seeds must be provided before bump",
1311 ));
1312 }
1313 self.bump.replace(c);
1314 Ok(())
1315 }
1316
1317 fn add_program_seed(&mut self, c: Context<ConstraintProgramSeed>) -> ParseResult<()> {
1318 if self.program_seed.is_some() {
1319 return Err(ParseError::new(c.span(), "seeds::program already provided"));
1320 }
1321 if self.seeds.is_none() {
1322 return Err(ParseError::new(
1323 c.span(),
1324 "seeds must be provided before seeds::program",
1325 ));
1326 }
1327 if let Some(ref init) = self.init {
1328 if init.if_needed {
1329 return Err(ParseError::new(
1330 c.span(),
1331 "seeds::program cannot be used with init_if_needed",
1332 ));
1333 } else {
1334 return Err(ParseError::new(
1335 c.span(),
1336 "seeds::program cannot be used with init",
1337 ));
1338 }
1339 }
1340 self.program_seed.replace(c);
1341 Ok(())
1342 }
1343
1344 fn add_token_authority(&mut self, c: Context<ConstraintTokenAuthority>) -> ParseResult<()> {
1345 if self.token_authority.is_some() {
1346 return Err(ParseError::new(
1347 c.span(),
1348 "token authority already provided",
1349 ));
1350 }
1351 self.token_authority.replace(c);
1352 Ok(())
1353 }
1354
1355 fn add_associated_token_authority(
1356 &mut self,
1357 c: Context<ConstraintTokenAuthority>,
1358 ) -> ParseResult<()> {
1359 if self.associated_token_authority.is_some() {
1360 return Err(ParseError::new(
1361 c.span(),
1362 "associated token authority already provided",
1363 ));
1364 }
1365 if self.token_authority.is_some() {
1366 return Err(ParseError::new(
1367 c.span(),
1368 "token authority already provided",
1369 ));
1370 }
1371 self.associated_token_authority.replace(c);
1372 Ok(())
1373 }
1374
1375 fn add_token_token_program(&mut self, c: Context<ConstraintTokenProgram>) -> ParseResult<()> {
1376 if self.token_token_program.is_some() {
1377 return Err(ParseError::new(
1378 c.span(),
1379 "token token_program already provided",
1380 ));
1381 }
1382 self.token_token_program.replace(c);
1383 Ok(())
1384 }
1385
1386 fn add_associated_token_token_program(
1387 &mut self,
1388 c: Context<ConstraintTokenProgram>,
1389 ) -> ParseResult<()> {
1390 if self.associated_token_token_program.is_some() {
1391 return Err(ParseError::new(
1392 c.span(),
1393 "associated token token_program already provided",
1394 ));
1395 }
1396 self.associated_token_token_program.replace(c);
1397 Ok(())
1398 }
1399
1400 fn add_mint_authority(&mut self, c: Context<ConstraintMintAuthority>) -> ParseResult<()> {
1401 if self.mint_authority.is_some() {
1402 return Err(ParseError::new(c.span(), "mint authority already provided"));
1403 }
1404 self.mint_authority.replace(c);
1405 Ok(())
1406 }
1407
1408 fn add_mint_freeze_authority(
1409 &mut self,
1410 c: Context<ConstraintMintFreezeAuthority>,
1411 ) -> ParseResult<()> {
1412 if self.mint_freeze_authority.is_some() {
1413 return Err(ParseError::new(
1414 c.span(),
1415 "mint freeze_authority already provided",
1416 ));
1417 }
1418 self.mint_freeze_authority.replace(c);
1419 Ok(())
1420 }
1421
1422 fn add_mint_decimals(&mut self, c: Context<ConstraintMintDecimals>) -> ParseResult<()> {
1423 if self.mint_decimals.is_some() {
1424 return Err(ParseError::new(c.span(), "mint decimals already provided"));
1425 }
1426 self.mint_decimals.replace(c);
1427 Ok(())
1428 }
1429
1430 fn add_mint_token_program(&mut self, c: Context<ConstraintTokenProgram>) -> ParseResult<()> {
1431 if self.mint_token_program.is_some() {
1432 return Err(ParseError::new(
1433 c.span(),
1434 "mint token_program already provided",
1435 ));
1436 }
1437 self.mint_token_program.replace(c);
1438 Ok(())
1439 }
1440
1441 fn add_mut(&mut self, c: Context<ConstraintMut>) -> ParseResult<()> {
1442 if self.mutable.is_some() {
1443 return Err(ParseError::new(c.span(), "mut already provided"));
1444 }
1445 self.mutable.replace(c);
1446 Ok(())
1447 }
1448
1449 fn add_signer(&mut self, c: Context<ConstraintSigner>) -> ParseResult<()> {
1450 if self.signer.is_some() {
1451 return Err(ParseError::new(c.span(), "signer already provided"));
1452 }
1453 self.signer.replace(c);
1454 Ok(())
1455 }
1456
1457 fn add_has_one(&mut self, c: Context<ConstraintHasOne>) -> ParseResult<()> {
1458 if self
1459 .has_one
1460 .iter()
1461 .filter(|item| item.join_target == c.join_target)
1462 .count()
1463 > 0
1464 {
1465 return Err(ParseError::new(c.span(), "has_one target already provided"));
1466 }
1467 self.has_one.push(c);
1468 Ok(())
1469 }
1470
1471 fn add_raw(&mut self, c: Context<ConstraintRaw>) -> ParseResult<()> {
1472 self.raw.push(c);
1473 Ok(())
1474 }
1475
1476 fn add_owner(&mut self, c: Context<ConstraintOwner>) -> ParseResult<()> {
1477 if self.owner.is_some() {
1478 return Err(ParseError::new(c.span(), "owner already provided"));
1479 }
1480 self.owner.replace(c);
1481 Ok(())
1482 }
1483
1484 fn add_rent_exempt(&mut self, c: Context<ConstraintRentExempt>) -> ParseResult<()> {
1485 if self.rent_exempt.is_some() {
1486 return Err(ParseError::new(c.span(), "rent already provided"));
1487 }
1488 self.rent_exempt.replace(c);
1489 Ok(())
1490 }
1491
1492 fn add_seeds(&mut self, c: Context<ConstraintSeeds>) -> ParseResult<()> {
1493 if self.seeds.is_some() {
1494 return Err(ParseError::new(c.span(), "seeds already provided"));
1495 }
1496 self.seeds.replace(c);
1497 Ok(())
1498 }
1499
1500 fn add_executable(&mut self, c: Context<ConstraintExecutable>) -> ParseResult<()> {
1501 if self.executable.is_some() {
1502 return Err(ParseError::new(c.span(), "executable already provided"));
1503 }
1504 self.executable.replace(c);
1505 Ok(())
1506 }
1507
1508 fn add_payer(&mut self, c: Context<ConstraintPayer>) -> ParseResult<()> {
1509 if self.init.is_none() {
1510 return Err(ParseError::new(
1511 c.span(),
1512 "init must be provided before payer",
1513 ));
1514 }
1515 if self.payer.is_some() {
1516 return Err(ParseError::new(c.span(), "payer already provided"));
1517 }
1518 self.payer.replace(c);
1519 Ok(())
1520 }
1521
1522 fn add_space(&mut self, c: Context<ConstraintSpace>) -> ParseResult<()> {
1523 if self.init.is_none() {
1524 return Err(ParseError::new(
1525 c.span(),
1526 "init must be provided before space",
1527 ));
1528 }
1529 if self.space.is_some() {
1530 return Err(ParseError::new(c.span(), "space already provided"));
1531 }
1532 self.space.replace(c);
1533 Ok(())
1534 }
1535
1536 fn add_extension_group_pointer_authority(
1539 &mut self,
1540 c: Context<ConstraintExtensionAuthority>,
1541 ) -> ParseResult<()> {
1542 if self.extension_group_pointer_authority.is_some() {
1543 return Err(ParseError::new(
1544 c.span(),
1545 "extension group pointer authority already provided",
1546 ));
1547 }
1548 self.extension_group_pointer_authority.replace(c);
1549 Ok(())
1550 }
1551
1552 fn add_extension_group_pointer_group_address(
1553 &mut self,
1554 c: Context<ConstraintExtensionGroupPointerGroupAddress>,
1555 ) -> ParseResult<()> {
1556 if self.extension_group_pointer_group_address.is_some() {
1557 return Err(ParseError::new(
1558 c.span(),
1559 "extension group pointer group address already provided",
1560 ));
1561 }
1562 self.extension_group_pointer_group_address.replace(c);
1563 Ok(())
1564 }
1565
1566 fn add_extension_group_member_pointer_authority(
1567 &mut self,
1568 c: Context<ConstraintExtensionAuthority>,
1569 ) -> ParseResult<()> {
1570 if self.extension_group_member_pointer_authority.is_some() {
1571 return Err(ParseError::new(
1572 c.span(),
1573 "extension group member pointer authority already provided",
1574 ));
1575 }
1576 self.extension_group_member_pointer_authority.replace(c);
1577 Ok(())
1578 }
1579
1580 fn add_extension_group_member_pointer_member_address(
1581 &mut self,
1582 c: Context<ConstraintExtensionGroupMemberPointerMemberAddress>,
1583 ) -> ParseResult<()> {
1584 if self.extension_group_member_pointer_member_address.is_some() {
1585 return Err(ParseError::new(
1586 c.span(),
1587 "extension group member pointer member address already provided",
1588 ));
1589 }
1590 self.extension_group_member_pointer_member_address
1591 .replace(c);
1592 Ok(())
1593 }
1594
1595 fn add_extension_metadata_pointer_authority(
1596 &mut self,
1597 c: Context<ConstraintExtensionAuthority>,
1598 ) -> ParseResult<()> {
1599 if self.extension_metadata_pointer_authority.is_some() {
1600 return Err(ParseError::new(
1601 c.span(),
1602 "extension metadata pointer authority already provided",
1603 ));
1604 }
1605 self.extension_metadata_pointer_authority.replace(c);
1606 Ok(())
1607 }
1608
1609 fn add_extension_metadata_pointer_metadata_address(
1610 &mut self,
1611 c: Context<ConstraintExtensionMetadataPointerMetadataAddress>,
1612 ) -> ParseResult<()> {
1613 if self.extension_metadata_pointer_metadata_address.is_some() {
1614 return Err(ParseError::new(
1615 c.span(),
1616 "extension metadata pointer metadata address already provided",
1617 ));
1618 }
1619 self.extension_metadata_pointer_metadata_address.replace(c);
1620 Ok(())
1621 }
1622
1623 fn add_extension_close_authority(
1624 &mut self,
1625 c: Context<ConstraintExtensionAuthority>,
1626 ) -> ParseResult<()> {
1627 if self.extension_close_authority.is_some() {
1628 return Err(ParseError::new(
1629 c.span(),
1630 "extension close authority already provided",
1631 ));
1632 }
1633 self.extension_close_authority.replace(c);
1634 Ok(())
1635 }
1636
1637 fn add_extension_authority(
1638 &mut self,
1639 c: Context<ConstraintExtensionAuthority>,
1640 ) -> ParseResult<()> {
1641 if self.extension_transfer_hook_authority.is_some() {
1642 return Err(ParseError::new(
1643 c.span(),
1644 "extension transfer hook authority already provided",
1645 ));
1646 }
1647 self.extension_transfer_hook_authority.replace(c);
1648 Ok(())
1649 }
1650
1651 fn add_extension_transfer_hook_program_id(
1652 &mut self,
1653 c: Context<ConstraintExtensionTokenHookProgramId>,
1654 ) -> ParseResult<()> {
1655 if self.extension_transfer_hook_program_id.is_some() {
1656 return Err(ParseError::new(
1657 c.span(),
1658 "extension transfer hook program id already provided",
1659 ));
1660 }
1661 self.extension_transfer_hook_program_id.replace(c);
1662 Ok(())
1663 }
1664
1665 fn add_extension_permanent_delegate(
1666 &mut self,
1667 c: Context<ConstraintExtensionPermanentDelegate>,
1668 ) -> ParseResult<()> {
1669 if self.extension_permanent_delegate.is_some() {
1670 return Err(ParseError::new(
1671 c.span(),
1672 "extension permanent delegate already provided",
1673 ));
1674 }
1675 self.extension_permanent_delegate.replace(c);
1676 Ok(())
1677 }
1678}