@@ -3,7 +3,7 @@ use proc_macro2::TokenStream;
33use quote:: { quote, ToTokens } ;
44
55use super :: common:: { get_idl_module_path, get_no_docs} ;
6- use crate :: { AccountField , AccountsStruct , Field , Ty } ;
6+ use crate :: { AccountField , AccountsStruct , Field , InitKind , Ty } ;
77
88/// Generate the IDL build impl for the Accounts struct.
99pub fn gen_idl_build_impl_accounts_struct ( accounts : & AccountsStruct ) -> TokenStream {
@@ -168,26 +168,87 @@ fn get_address(acc: &Field) -> TokenStream {
168168
169169fn get_pda ( acc : & Field , accounts : & AccountsStruct ) -> TokenStream {
170170 let idl = get_idl_module_path ( ) ;
171+ let parse_default = |expr : & syn:: Expr | parse_seed ( expr, accounts) ;
172+
173+ // Seeds
171174 let seed_constraints = acc. constraints . seeds . as_ref ( ) ;
172- let seeds = seed_constraints
173- . map ( |seed| seed. seeds . iter ( ) . map ( |seed| parse_seed ( seed, accounts) ) )
174- . and_then ( |seeds| seeds. collect :: < Result < Vec < _ > > > ( ) . ok ( ) ) ;
175- let program = seed_constraints
176- . and_then ( |seed| seed. program_seed . as_ref ( ) )
177- . and_then ( |program| parse_seed ( program, accounts) . ok ( ) )
178- . map ( |program| quote ! { Some ( #program) } )
179- . unwrap_or_else ( || quote ! { None } ) ;
180- match seeds {
181- Some ( seeds) => quote ! {
182- Some (
183- #idl:: IdlPda {
184- seeds: vec![ #( #seeds) , * ] ,
185- program: #program,
186- }
187- )
188- } ,
189- _ => quote ! { None } ,
175+ let pda = seed_constraints
176+ . map ( |seed| seed. seeds . iter ( ) . map ( parse_default) )
177+ . and_then ( |seeds| seeds. collect :: < Result < Vec < _ > > > ( ) . ok ( ) )
178+ . map ( |seeds| {
179+ let program = seed_constraints
180+ . and_then ( |seed| seed. program_seed . as_ref ( ) )
181+ . and_then ( |program| parse_default ( program) . ok ( ) )
182+ . map ( |program| quote ! { Some ( #program) } )
183+ . unwrap_or_else ( || quote ! { None } ) ;
184+
185+ quote ! {
186+ Some (
187+ #idl:: IdlPda {
188+ seeds: vec![ #( #seeds) , * ] ,
189+ program: #program,
190+ }
191+ )
192+ }
193+ } ) ;
194+ if let Some ( pda) = pda {
195+ return pda;
190196 }
197+
198+ // Associated token
199+ let pda = acc
200+ . constraints
201+ . init
202+ . as_ref ( )
203+ . and_then ( |init| match & init. kind {
204+ InitKind :: AssociatedToken {
205+ owner,
206+ mint,
207+ token_program,
208+ } => Some ( ( owner, mint, token_program) ) ,
209+ _ => None ,
210+ } )
211+ . or_else ( || {
212+ acc. constraints
213+ . associated_token
214+ . as_ref ( )
215+ . map ( |ata| ( & ata. wallet , & ata. mint , & ata. token_program ) )
216+ } )
217+ . and_then ( |( wallet, mint, token_program) | {
218+ // ATA constraints have implicit `.key()` call
219+ let parse_expr = |ts| parse_default ( & syn:: parse2 ( ts) . unwrap ( ) ) . ok ( ) ;
220+ let parse_ata = |expr| parse_expr ( quote ! { #expr. key( ) . as_ref( ) } ) ;
221+
222+ let wallet = parse_ata ( wallet) ;
223+ let mint = parse_ata ( mint) ;
224+ let token_program = token_program
225+ . as_ref ( )
226+ . and_then ( parse_ata)
227+ . or_else ( || parse_expr ( quote ! ( anchor_spl:: token:: ID ) ) ) ;
228+
229+ let seeds = match ( wallet, mint, token_program) {
230+ ( Some ( w) , Some ( m) , Some ( tp) ) => quote ! { vec![ #w, #tp, #m] } ,
231+ _ => return None ,
232+ } ;
233+
234+ let program = parse_expr ( quote ! ( anchor_spl:: associated_token:: ID ) )
235+ . map ( |program| quote ! { Some ( #program) } )
236+ . unwrap ( ) ;
237+
238+ Some ( quote ! {
239+ Some (
240+ #idl:: IdlPda {
241+ seeds: #seeds,
242+ program: #program,
243+ }
244+ )
245+ } )
246+ } ) ;
247+ if let Some ( pda) = pda {
248+ return pda;
249+ }
250+
251+ quote ! { None }
191252}
192253
193254/// Parse a seeds constraint, extracting the `IdlSeed` types.
0 commit comments