use trident_idl_spec::{
Idl, IdlInstructionAccount, IdlInstructionAccountItem, IdlInstructionAccounts,
};
use quote::format_ident;
use std::collections::HashMap;
use syn::parse_quote;
use crate::instruction_account::{FuzzAccountsType, InstructionAccount};
pub(crate) fn get_fuzz_accounts(
idl: &Idl,
instructions_accounts: &HashMap<String, InstructionAccount>,
) -> Vec<syn::FnArg> {
let fuzz_accounts = idl.instructions.iter().fold(
HashMap::new(),
|mut fuzz_accounts: HashMap<syn::Ident, syn::FnArg>, instruction| {
instruction
.accounts
.iter()
.fold(&mut fuzz_accounts, |fuzz_accounts, account| {
match account {
IdlInstructionAccountItem::Composite(idl_instruction_accounts) => {
process_composite_account(
idl_instruction_accounts,
fuzz_accounts,
instructions_accounts,
);
}
IdlInstructionAccountItem::Single(idl_instruction_account) => {
process_single_account(
idl_instruction_account,
fuzz_accounts,
instructions_accounts,
);
}
};
fuzz_accounts
});
fuzz_accounts
},
);
let mut sorted_accounts: Vec<_> = fuzz_accounts.into_iter().collect();
sorted_accounts.sort_by(|(k1, _), (k2, _)| k1.cmp(k2));
sorted_accounts.into_iter().map(|(_, v)| v).collect()
}
fn process_composite_account(
idl_instruction_accounts: &IdlInstructionAccounts,
fuzz_accounts: &mut HashMap<syn::Ident, syn::FnArg>,
instructions_accounts: &HashMap<String, InstructionAccount>,
) {
for account in &idl_instruction_accounts.accounts {
match account {
IdlInstructionAccountItem::Single(idl_instruction_account) => {
process_single_account(
idl_instruction_account,
fuzz_accounts,
instructions_accounts,
);
}
IdlInstructionAccountItem::Composite(idl_instruction_accounts) => {
process_composite_account(
idl_instruction_accounts,
fuzz_accounts,
instructions_accounts,
);
}
}
}
}
fn process_single_account(
idl_instruction_account: &IdlInstructionAccount,
fuzz_accounts: &mut HashMap<syn::Ident, syn::FnArg>,
instructions_accounts: &HashMap<String, InstructionAccount>,
) {
let account = instructions_accounts
.get(&idl_instruction_account.name)
.expect("Account not found in types databse");
let account_type = account.get_fuzz_accounts_type();
match account_type {
FuzzAccountsType::Keypair => {
process_keypair_account(idl_instruction_account, fuzz_accounts);
}
FuzzAccountsType::Pda => {
process_pda_account(idl_instruction_account, fuzz_accounts);
}
FuzzAccountsType::Constant => {
}
FuzzAccountsType::Unknown => {
process_unknown_account(idl_instruction_account, fuzz_accounts);
}
}
}
fn process_keypair_account(
idl_instruction_account: &IdlInstructionAccount,
fuzz_accounts: &mut HashMap<syn::Ident, syn::FnArg>,
) {
let name: syn::Ident = format_ident!("{}", &idl_instruction_account.name);
let account = parse_quote! { #name: AccountsStorage<KeypairStore> };
fuzz_accounts.entry(name).or_insert(account);
}
fn process_pda_account(
idl_instruction_account: &IdlInstructionAccount,
fuzz_accounts: &mut HashMap<syn::Ident, syn::FnArg>,
) {
let name: syn::Ident = format_ident!("{}", &idl_instruction_account.name);
let account = parse_quote! { #name: AccountsStorage<PdaStore> };
fuzz_accounts.entry(name).or_insert(account);
}
fn process_unknown_account(
idl_instruction_account: &IdlInstructionAccount,
fuzz_accounts: &mut HashMap<syn::Ident, syn::FnArg>,
) {
let name: syn::Ident = format_ident!("{}", &idl_instruction_account.name);
let account = parse_quote! { #name: AccountsStorage<todo!()> };
fuzz_accounts.entry(name).or_insert(account);
}