1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2
3pub mod codegen;
4pub mod parser;
5
6#[cfg(feature = "idl-types")]
7pub mod idl;
8
9#[cfg(feature = "hash")]
10pub mod hash;
11#[cfg(not(feature = "hash"))]
12pub(crate) mod hash;
13
14use codegen::accounts as accounts_codegen;
15use codegen::program as program_codegen;
16use parser::accounts as accounts_parser;
17use parser::program as program_parser;
18use proc_macro2::{Span, TokenStream};
19use quote::quote;
20use quote::ToTokens;
21use std::collections::HashMap;
22use std::ops::Deref;
23use syn::ext::IdentExt;
24use syn::parse::{Error as ParseError, Parse, ParseStream, Result as ParseResult};
25use syn::punctuated::Punctuated;
26use syn::spanned::Spanned;
27use syn::token::Comma;
28use syn::{
29 Expr, Generics, Ident, ItemEnum, ItemFn, ItemMod, ItemStruct, LitInt, PatType, Token, Type,
30 TypePath,
31};
32
33#[derive(Debug)]
34pub struct Program {
35 pub ixs: Vec<Ix>,
36 pub name: Ident,
37 pub docs: Option<Vec<String>>,
38 pub program_mod: ItemMod,
39 pub fallback_fn: Option<FallbackFn>,
40}
41
42impl Parse for Program {
43 fn parse(input: ParseStream) -> ParseResult<Self> {
44 let program_mod = <ItemMod as Parse>::parse(input)?;
45 program_parser::parse(program_mod)
46 }
47}
48
49impl From<&Program> for TokenStream {
50 fn from(program: &Program) -> Self {
51 program_codegen::generate(program)
52 }
53}
54
55impl ToTokens for Program {
56 fn to_tokens(&self, tokens: &mut TokenStream) {
57 tokens.extend::<TokenStream>(self.into());
58 }
59}
60
61#[derive(Debug)]
62pub struct Ix {
63 pub raw_method: ItemFn,
64 pub ident: Ident,
65 pub docs: Option<Vec<String>>,
66 pub args: Vec<IxArg>,
67 pub returns: IxReturn,
68 pub anchor_ident: Ident,
70 pub interface_discriminator: Option<[u8; 8]>,
72}
73
74#[derive(Debug)]
75pub struct IxArg {
76 pub name: Ident,
77 pub docs: Option<Vec<String>>,
78 pub raw_arg: PatType,
79}
80
81#[derive(Debug)]
82pub struct IxReturn {
83 pub ty: Type,
84}
85
86#[derive(Debug)]
87pub struct FallbackFn {
88 raw_method: ItemFn,
89}
90
91#[derive(Debug)]
92pub struct AccountsStruct {
93 pub ident: Ident,
95 pub generics: Generics,
97 pub fields: Vec<AccountField>,
99 instruction_api: Option<Punctuated<Expr, Comma>>,
101}
102
103impl Parse for AccountsStruct {
104 fn parse(input: ParseStream) -> ParseResult<Self> {
105 let strct = <ItemStruct as Parse>::parse(input)?;
106 accounts_parser::parse(&strct)
107 }
108}
109
110impl From<&AccountsStruct> for TokenStream {
111 fn from(accounts: &AccountsStruct) -> Self {
112 accounts_codegen::generate(accounts)
113 }
114}
115
116impl ToTokens for AccountsStruct {
117 fn to_tokens(&self, tokens: &mut TokenStream) {
118 tokens.extend::<TokenStream>(self.into());
119 }
120}
121
122impl AccountsStruct {
123 pub fn new(
124 strct: ItemStruct,
125 fields: Vec<AccountField>,
126 instruction_api: Option<Punctuated<Expr, Comma>>,
127 ) -> Self {
128 let ident = strct.ident.clone();
129 let generics = strct.generics;
130 Self {
131 ident,
132 generics,
133 fields,
134 instruction_api,
135 }
136 }
137
138 pub fn instruction_args(&self) -> Option<HashMap<String, String>> {
142 self.instruction_api.as_ref().map(|instruction_api| {
143 instruction_api
144 .iter()
145 .map(|expr| {
146 let arg = parser::tts_to_string(expr);
147 let components: Vec<&str> = arg.split(" : ").collect();
148 assert!(components.len() == 2);
149 (components[0].to_string(), components[1].to_string())
150 })
151 .collect()
152 })
153 }
154
155 pub fn field_names(&self) -> Vec<String> {
156 self.fields
157 .iter()
158 .map(|field| field.ident().to_string())
159 .collect()
160 }
161
162 pub fn has_optional(&self) -> bool {
163 for field in &self.fields {
164 if let AccountField::Field(field) = field {
165 if field.is_optional {
166 return true;
167 }
168 }
169 }
170 false
171 }
172
173 pub fn is_field_optional<T: quote::ToTokens>(&self, field: &T) -> bool {
174 let matching_field = self
175 .fields
176 .iter()
177 .find(|f| *f.ident() == parser::tts_to_string(field));
178 if let Some(matching_field) = matching_field {
179 matching_field.is_optional()
180 } else {
181 false
182 }
183 }
184}
185
186#[allow(clippy::large_enum_variant)]
187#[derive(Debug)]
188pub enum AccountField {
189 Field(Field),
190 CompositeField(CompositeField),
191}
192
193impl AccountField {
194 fn ident(&self) -> &Ident {
195 match self {
196 AccountField::Field(field) => &field.ident,
197 AccountField::CompositeField(c_field) => &c_field.ident,
198 }
199 }
200
201 fn is_optional(&self) -> bool {
202 match self {
203 AccountField::Field(field) => field.is_optional,
204 AccountField::CompositeField(_) => false,
205 }
206 }
207
208 pub fn ty_name(&self) -> Option<String> {
209 let qualified_ty_name = match self {
210 AccountField::Field(field) => match &field.ty {
211 Ty::Account(account) => Some(parser::tts_to_string(&account.account_type_path)),
212 _ => None,
213 },
214 AccountField::CompositeField(field) => Some(field.symbol.clone()),
215 };
216
217 qualified_ty_name.map(|name| match name.rsplit_once(" :: ") {
218 Some((_prefix, suffix)) => suffix.to_string(),
219 None => name,
220 })
221 }
222}
223
224#[derive(Debug)]
225pub struct Field {
226 pub ident: Ident,
227 pub constraints: ConstraintGroup,
228 pub ty: Ty,
229 pub is_optional: bool,
230 pub docs: Option<Vec<String>>,
232}
233
234impl Field {
235 pub fn typed_ident(&self) -> proc_macro2::TokenStream {
236 let name = &self.ident;
237 let ty_decl = self.ty_decl(false);
238 quote! {
239 #name: #ty_decl
240 }
241 }
242
243 pub fn ty_decl(&self, ignore_option: bool) -> proc_macro2::TokenStream {
244 let account_ty = self.account_ty();
245 let container_ty = self.container_ty();
246 let inner_ty = match &self.ty {
247 Ty::AccountInfo => quote! {
248 AccountInfo
249 },
250 Ty::UncheckedAccount => quote! {
251 UncheckedAccount
252 },
253 Ty::Signer => quote! {
254 Signer
255 },
256 Ty::ProgramData => quote! {
257 ProgramData
258 },
259 Ty::SystemAccount => quote! {
260 SystemAccount
261 },
262 Ty::Account(AccountTy { boxed, .. })
263 | Ty::InterfaceAccount(InterfaceAccountTy { boxed, .. }) => {
264 if *boxed {
265 quote! {
266 Box<#container_ty<#account_ty>>
267 }
268 } else {
269 quote! {
270 #container_ty<#account_ty>
271 }
272 }
273 }
274 Ty::Sysvar(ty) => {
275 let account = match ty {
276 SysvarTy::Clock => quote! {Clock},
277 SysvarTy::Rent => quote! {Rent},
278 SysvarTy::EpochSchedule => quote! {EpochSchedule},
279 SysvarTy::Fees => quote! {Fees},
280 SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
281 SysvarTy::SlotHashes => quote! {SlotHashes},
282 SysvarTy::SlotHistory => quote! {SlotHistory},
283 SysvarTy::StakeHistory => quote! {StakeHistory},
284 SysvarTy::Instructions => quote! {Instructions},
285 SysvarTy::Rewards => quote! {Rewards},
286 };
287 quote! {
288 Sysvar<#account>
289 }
290 }
291 _ => quote! {
292 #container_ty<#account_ty>
293 },
294 };
295 if self.is_optional && !ignore_option {
296 quote! {
297 Option<#inner_ty>
298 }
299 } else {
300 quote! {
301 #inner_ty
302 }
303 }
304 }
305
306 pub fn from_account_info(
309 &self,
310 kind: Option<&InitKind>,
311 checked: bool,
312 ) -> proc_macro2::TokenStream {
313 let field = &self.ident;
314 let field_str = field.to_string();
315 let container_ty = self.container_ty();
316 let owner_addr = match &kind {
317 None => quote! { __program_id },
318 Some(InitKind::Program { .. }) => quote! {
319 __program_id
320 },
321 _ => quote! {
322 &anchor_spl::token::ID
323 },
324 };
325 match &self.ty {
326 Ty::AccountInfo => quote! { #field.to_account_info() },
327 Ty::UncheckedAccount => {
328 quote! { UncheckedAccount::try_from(&#field) }
329 }
330 Ty::Account(AccountTy { boxed, .. })
331 | Ty::InterfaceAccount(InterfaceAccountTy { boxed, .. }) => {
332 let stream = if checked {
333 quote! {
334 match #container_ty::try_from(&#field) {
335 Ok(val) => val,
336 Err(e) => return Err(e.with_account_name(#field_str))
337 }
338 }
339 } else {
340 quote! {
341 match #container_ty::try_from_unchecked(&#field) {
342 Ok(val) => val,
343 Err(e) => return Err(e.with_account_name(#field_str))
344 }
345 }
346 };
347 if *boxed {
348 quote! {
349 Box::new(#stream)
350 }
351 } else {
352 stream
353 }
354 }
355 Ty::AccountLoader(_) => {
356 if checked {
357 quote! {
358 match #container_ty::try_from(&#field) {
359 Ok(val) => val,
360 Err(e) => return Err(e.with_account_name(#field_str))
361 }
362 }
363 } else {
364 quote! {
365 match #container_ty::try_from_unchecked(#owner_addr, &#field) {
366 Ok(val) => val,
367 Err(e) => return Err(e.with_account_name(#field_str))
368 }
369 }
370 }
371 }
372 _ => {
373 if checked {
374 quote! {
375 match #container_ty::try_from(#owner_addr, &#field) {
376 Ok(val) => val,
377 Err(e) => return Err(e.with_account_name(#field_str))
378 }
379 }
380 } else {
381 quote! {
382 match #container_ty::try_from_unchecked(#owner_addr, &#field) {
383 Ok(val) => val,
384 Err(e) => return Err(e.with_account_name(#field_str))
385 }
386 }
387 }
388 }
389 }
390 }
391
392 pub fn container_ty(&self) -> proc_macro2::TokenStream {
393 match &self.ty {
394 Ty::Account(_) => quote! {
395 anchor_lang::accounts::account::Account
396 },
397 Ty::AccountLoader(_) => quote! {
398 anchor_lang::accounts::account_loader::AccountLoader
399 },
400 Ty::Sysvar(_) => quote! { anchor_lang::accounts::sysvar::Sysvar },
401 Ty::Program(_) => quote! { anchor_lang::accounts::program::Program },
402 Ty::Interface(_) => quote! { anchor_lang::accounts::interface::Interface },
403 Ty::InterfaceAccount(_) => {
404 quote! { anchor_lang::accounts::interface_account::InterfaceAccount }
405 }
406 Ty::AccountInfo => quote! {},
407 Ty::UncheckedAccount => quote! {},
408 Ty::Signer => quote! {},
409 Ty::SystemAccount => quote! {},
410 Ty::ProgramData => quote! {},
411 }
412 }
413
414 pub fn account_ty(&self) -> proc_macro2::TokenStream {
416 match &self.ty {
417 Ty::AccountInfo => quote! {
418 AccountInfo
419 },
420 Ty::UncheckedAccount => quote! {
421 UncheckedAccount
422 },
423 Ty::Signer => quote! {
424 Signer
425 },
426 Ty::SystemAccount => quote! {
427 SystemAccount
428 },
429 Ty::ProgramData => quote! {
430 ProgramData
431 },
432 Ty::Account(ty) => {
433 let ident = &ty.account_type_path;
434 quote! {
435 #ident
436 }
437 }
438 Ty::InterfaceAccount(ty) => {
439 let ident = &ty.account_type_path;
440 quote! {
441 #ident
442 }
443 }
444 Ty::AccountLoader(ty) => {
445 let ident = &ty.account_type_path;
446 quote! {
447 #ident
448 }
449 }
450 Ty::Sysvar(ty) => match ty {
451 SysvarTy::Clock => quote! {Clock},
452 SysvarTy::Rent => quote! {Rent},
453 SysvarTy::EpochSchedule => quote! {EpochSchedule},
454 SysvarTy::Fees => quote! {Fees},
455 SysvarTy::RecentBlockhashes => quote! {RecentBlockhashes},
456 SysvarTy::SlotHashes => quote! {SlotHashes},
457 SysvarTy::SlotHistory => quote! {SlotHistory},
458 SysvarTy::StakeHistory => quote! {StakeHistory},
459 SysvarTy::Instructions => quote! {Instructions},
460 SysvarTy::Rewards => quote! {Rewards},
461 },
462 Ty::Program(ty) => {
463 let program = &ty.account_type_path;
464 quote! {
465 #program
466 }
467 }
468 Ty::Interface(ty) => {
469 let program = &ty.account_type_path;
470 quote! {
471 #program
472 }
473 }
474 }
475 }
476}
477
478#[derive(Debug)]
479pub struct CompositeField {
480 pub ident: Ident,
481 pub constraints: ConstraintGroup,
482 pub symbol: String,
483 pub raw_field: syn::Field,
484 pub docs: Option<Vec<String>>,
486}
487
488#[derive(Debug, PartialEq, Eq)]
490pub enum Ty {
491 AccountInfo,
492 UncheckedAccount,
493 AccountLoader(AccountLoaderTy),
494 Sysvar(SysvarTy),
495 Account(AccountTy),
496 Program(ProgramTy),
497 Interface(InterfaceTy),
498 InterfaceAccount(InterfaceAccountTy),
499 Signer,
500 SystemAccount,
501 ProgramData,
502}
503
504#[derive(Debug, PartialEq, Eq)]
505pub enum SysvarTy {
506 Clock,
507 Rent,
508 EpochSchedule,
509 Fees,
510 RecentBlockhashes,
511 SlotHashes,
512 SlotHistory,
513 StakeHistory,
514 Instructions,
515 Rewards,
516}
517
518#[derive(Debug, PartialEq, Eq)]
519pub struct AccountLoaderTy {
520 pub account_type_path: TypePath,
522}
523
524#[derive(Debug, PartialEq, Eq)]
525pub struct AccountTy {
526 pub account_type_path: TypePath,
528 pub boxed: bool,
530}
531
532#[derive(Debug, PartialEq, Eq)]
533pub struct InterfaceAccountTy {
534 pub account_type_path: TypePath,
536 pub boxed: bool,
538}
539
540#[derive(Debug, PartialEq, Eq)]
541pub struct ProgramTy {
542 pub account_type_path: TypePath,
544}
545
546#[derive(Debug, PartialEq, Eq)]
547pub struct InterfaceTy {
548 pub account_type_path: TypePath,
550}
551
552#[derive(Debug)]
553pub struct Error {
554 pub name: String,
555 pub raw_enum: ItemEnum,
556 pub ident: Ident,
557 pub codes: Vec<ErrorCode>,
558 pub args: Option<ErrorArgs>,
559}
560
561#[derive(Debug)]
562pub struct ErrorArgs {
563 pub offset: LitInt,
564}
565
566impl Parse for ErrorArgs {
567 fn parse(stream: ParseStream) -> ParseResult<Self> {
568 let offset_span = stream.span();
569 let offset = stream.call(Ident::parse_any)?;
570 if offset.to_string().as_str() != "offset" {
571 return Err(ParseError::new(offset_span, "expected keyword offset"));
572 }
573 stream.parse::<Token![=]>()?;
574 Ok(ErrorArgs {
575 offset: stream.parse()?,
576 })
577 }
578}
579
580#[derive(Debug)]
581pub struct ErrorCode {
582 pub id: u32,
583 pub ident: Ident,
584 pub msg: Option<String>,
585}
586
587#[derive(Debug, Default, Clone)]
589pub struct ConstraintGroup {
590 pub init: Option<ConstraintInitGroup>,
591 pub zeroed: Option<ConstraintZeroed>,
592 pub mutable: Option<ConstraintMut>,
593 pub signer: Option<ConstraintSigner>,
594 pub owner: Option<ConstraintOwner>,
595 pub rent_exempt: Option<ConstraintRentExempt>,
596 pub seeds: Option<ConstraintSeedsGroup>,
597 pub executable: Option<ConstraintExecutable>,
598 pub has_one: Vec<ConstraintHasOne>,
599 pub raw: Vec<ConstraintRaw>,
600 pub close: Option<ConstraintClose>,
601 pub address: Option<ConstraintAddress>,
602 pub associated_token: Option<ConstraintAssociatedToken>,
603 pub token_account: Option<ConstraintTokenAccountGroup>,
604 pub mint: Option<ConstraintTokenMintGroup>,
605 pub realloc: Option<ConstraintReallocGroup>,
606}
607
608impl ConstraintGroup {
609 pub fn is_zeroed(&self) -> bool {
610 self.zeroed.is_some()
611 }
612
613 pub fn is_mutable(&self) -> bool {
614 self.mutable.is_some()
615 }
616
617 pub fn is_signer(&self) -> bool {
618 self.signer.is_some()
619 }
620
621 pub fn is_close(&self) -> bool {
622 self.close.is_some()
623 }
624}
625
626#[allow(clippy::large_enum_variant)]
630#[derive(Debug)]
631pub enum Constraint {
632 Init(ConstraintInitGroup),
633 Zeroed(ConstraintZeroed),
634 Mut(ConstraintMut),
635 Signer(ConstraintSigner),
636 HasOne(ConstraintHasOne),
637 Raw(ConstraintRaw),
638 Owner(ConstraintOwner),
639 RentExempt(ConstraintRentExempt),
640 Seeds(ConstraintSeedsGroup),
641 AssociatedToken(ConstraintAssociatedToken),
642 Executable(ConstraintExecutable),
643 Close(ConstraintClose),
644 Address(ConstraintAddress),
645 TokenAccount(ConstraintTokenAccountGroup),
646 Mint(ConstraintTokenMintGroup),
647 Realloc(ConstraintReallocGroup),
648}
649
650#[allow(clippy::large_enum_variant)]
652#[derive(Debug)]
653pub enum ConstraintToken {
654 Init(Context<ConstraintInit>),
655 Zeroed(Context<ConstraintZeroed>),
656 Mut(Context<ConstraintMut>),
657 Signer(Context<ConstraintSigner>),
658 HasOne(Context<ConstraintHasOne>),
659 Raw(Context<ConstraintRaw>),
660 Owner(Context<ConstraintOwner>),
661 RentExempt(Context<ConstraintRentExempt>),
662 Seeds(Context<ConstraintSeeds>),
663 Executable(Context<ConstraintExecutable>),
664 Close(Context<ConstraintClose>),
665 Payer(Context<ConstraintPayer>),
666 Space(Context<ConstraintSpace>),
667 Address(Context<ConstraintAddress>),
668 TokenMint(Context<ConstraintTokenMint>),
669 TokenAuthority(Context<ConstraintTokenAuthority>),
670 TokenTokenProgram(Context<ConstraintTokenProgram>),
671 AssociatedTokenMint(Context<ConstraintTokenMint>),
672 AssociatedTokenAuthority(Context<ConstraintTokenAuthority>),
673 AssociatedTokenTokenProgram(Context<ConstraintTokenProgram>),
674 MintAuthority(Context<ConstraintMintAuthority>),
675 MintFreezeAuthority(Context<ConstraintMintFreezeAuthority>),
676 MintDecimals(Context<ConstraintMintDecimals>),
677 MintTokenProgram(Context<ConstraintTokenProgram>),
678 Bump(Context<ConstraintTokenBump>),
679 ProgramSeed(Context<ConstraintProgramSeed>),
680 Realloc(Context<ConstraintRealloc>),
681 ReallocPayer(Context<ConstraintReallocPayer>),
682 ReallocZero(Context<ConstraintReallocZero>),
683}
684
685impl Parse for ConstraintToken {
686 fn parse(stream: ParseStream) -> ParseResult<Self> {
687 accounts_parser::constraints::parse_token(stream)
688 }
689}
690
691#[derive(Debug, Clone)]
692pub struct ConstraintInit {
693 pub if_needed: bool,
694}
695
696#[derive(Debug, Clone)]
697pub struct ConstraintInitIfNeeded {}
698
699#[derive(Debug, Clone)]
700pub struct ConstraintZeroed {}
701
702#[derive(Debug, Clone)]
703pub struct ConstraintMut {
704 pub error: Option<Expr>,
705}
706
707#[derive(Debug, Clone)]
708pub struct ConstraintReallocGroup {
709 pub payer: Expr,
710 pub space: Expr,
711 pub zero: Expr,
712}
713
714#[derive(Debug, Clone)]
715pub struct ConstraintRealloc {
716 pub space: Expr,
717}
718
719#[derive(Debug, Clone)]
720pub struct ConstraintReallocPayer {
721 pub target: Expr,
722}
723
724#[derive(Debug, Clone)]
725pub struct ConstraintReallocZero {
726 pub zero: Expr,
727}
728
729#[derive(Debug, Clone)]
730pub struct ConstraintSigner {
731 pub error: Option<Expr>,
732}
733
734#[derive(Debug, Clone)]
735pub struct ConstraintHasOne {
736 pub join_target: Expr,
737 pub error: Option<Expr>,
738}
739
740#[derive(Debug, Clone)]
741pub struct ConstraintRaw {
742 pub raw: Expr,
743 pub error: Option<Expr>,
744}
745
746#[derive(Debug, Clone)]
747pub struct ConstraintOwner {
748 pub owner_address: Expr,
749 pub error: Option<Expr>,
750}
751
752#[derive(Debug, Clone)]
753pub struct ConstraintAddress {
754 pub address: Expr,
755 pub error: Option<Expr>,
756}
757
758#[derive(Debug, Clone)]
759pub enum ConstraintRentExempt {
760 Enforce,
761 Skip,
762}
763
764#[derive(Debug, Clone)]
765pub struct ConstraintInitGroup {
766 pub if_needed: bool,
767 pub seeds: Option<ConstraintSeedsGroup>,
768 pub payer: Expr,
769 pub space: Option<Expr>,
770 pub kind: InitKind,
771}
772
773#[derive(Debug, Clone)]
774pub struct ConstraintSeedsGroup {
775 pub is_init: bool,
776 pub seeds: Punctuated<Expr, Token![,]>,
777 pub bump: Option<Expr>, pub program_seed: Option<Expr>, }
780
781#[derive(Debug, Clone)]
782pub struct ConstraintSeeds {
783 pub seeds: Punctuated<Expr, Token![,]>,
784}
785
786#[derive(Debug, Clone)]
787pub struct ConstraintExecutable {}
788
789#[derive(Debug, Clone)]
790pub struct ConstraintPayer {
791 pub target: Expr,
792}
793
794#[derive(Debug, Clone)]
795pub struct ConstraintSpace {
796 pub space: Expr,
797}
798
799#[derive(Debug, Clone)]
800#[allow(clippy::large_enum_variant)]
801pub enum InitKind {
802 Program {
803 owner: Option<Expr>,
804 },
805 Interface {
806 owner: Option<Expr>,
807 },
808 Token {
811 owner: Expr,
812 mint: Expr,
813 token_program: Option<Expr>,
814 },
815 AssociatedToken {
816 owner: Expr,
817 mint: Expr,
818 token_program: Option<Expr>,
819 },
820 Mint {
821 owner: Expr,
822 freeze_authority: Option<Expr>,
823 decimals: Expr,
824 token_program: Option<Expr>,
825 },
826}
827
828#[derive(Debug, Clone)]
829pub struct ConstraintClose {
830 pub sol_dest: Ident,
831}
832
833#[derive(Debug, Clone)]
834pub struct ConstraintTokenMint {
835 pub mint: Expr,
836}
837
838#[derive(Debug, Clone)]
839pub struct ConstraintTokenAuthority {
840 pub auth: Expr,
841}
842
843#[derive(Debug, Clone)]
844pub struct ConstraintTokenProgram {
845 token_program: Expr,
846}
847
848#[derive(Debug, Clone)]
849pub struct ConstraintMintAuthority {
850 pub mint_auth: Expr,
851}
852
853#[derive(Debug, Clone)]
854pub struct ConstraintMintFreezeAuthority {
855 pub mint_freeze_auth: Expr,
856}
857
858#[derive(Debug, Clone)]
859pub struct ConstraintMintDecimals {
860 pub decimals: Expr,
861}
862
863#[derive(Debug, Clone)]
864pub struct ConstraintTokenBump {
865 pub bump: Option<Expr>,
866}
867
868#[derive(Debug, Clone)]
869pub struct ConstraintProgramSeed {
870 pub program_seed: Expr,
871}
872
873#[derive(Debug, Clone)]
874pub struct ConstraintAssociatedToken {
875 pub wallet: Expr,
876 pub mint: Expr,
877 pub token_program: Option<Expr>,
878}
879
880#[derive(Debug, Clone)]
881pub struct ConstraintTokenAccountGroup {
882 pub mint: Option<Expr>,
883 pub authority: Option<Expr>,
884 pub token_program: Option<Expr>,
885}
886
887#[derive(Debug, Clone)]
888pub struct ConstraintTokenMintGroup {
889 pub decimals: Option<Expr>,
890 pub mint_authority: Option<Expr>,
891 pub freeze_authority: Option<Expr>,
892 pub token_program: Option<Expr>,
893}
894
895#[derive(Debug, Clone)]
897pub struct Context<T> {
898 span: Span,
899 inner: T,
900}
901
902impl<T> Context<T> {
903 pub fn new(span: Span, inner: T) -> Self {
904 Self { span, inner }
905 }
906
907 pub fn into_inner(self) -> T {
908 self.inner
909 }
910}
911
912impl<T> Deref for Context<T> {
913 type Target = T;
914
915 fn deref(&self) -> &Self::Target {
916 &self.inner
917 }
918}
919
920impl<T> Spanned for Context<T> {
921 fn span(&self) -> Span {
922 self.span
923 }
924}