anchor_syn/parser/accounts/
constraints.rs

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
23// Parses a single constraint from a parse stream for `#[account(<STREAM>)]`.
24pub 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        // Init.
596        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            // Rent exempt if not explicitly skipped.
620            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            // When initializing a non-PDA account, the account being
631            // initialized must sign to invoke the system program's create
632            // account instruction.
633            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            // Assert a bump target is not given on init.
640            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            // TokenAccount.
650            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            // Mint.
668            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        // Realloc.
687        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        // Zero.
703        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            // Rent exempt if not explicitly skipped.
716            if self.rent_exempt.is_none() {
717                self.rent_exempt
718                    .replace(Context::new(z.span(), ConstraintRentExempt::Enforce));
719            }
720        }
721
722        // Seeds.
723        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        // Space.
739        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        // Converts Option<Context<T>> -> Option<T>.
806        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        // Converts Vec<Context<T>> - Vec<T>.
815        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                // extensions
928                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                        // extensions
998                        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        // Require a known account type that implements the `Discriminator` trait so that we can
1179        // get the discriminator length dynamically
1180        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    // extensions
1537
1538    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}