|
@@ -69,39 +69,14 @@ pub fn generate_dispatch(program: &Program) -> proc_macro2::TokenStream {
|
|
// Dispatch the state constructor.
|
|
// Dispatch the state constructor.
|
|
let ctor_state_dispatch_arm = match &program.state {
|
|
let ctor_state_dispatch_arm = match &program.state {
|
|
None => quote! { /* no-op */ },
|
|
None => quote! { /* no-op */ },
|
|
- Some(state) => {
|
|
|
|
- let variant_arm = generate_ctor_variant(state);
|
|
|
|
- let ctor_args = generate_ctor_args(state);
|
|
|
|
- let ix_name: proc_macro2::TokenStream = generate_ctor_variant_name().parse().unwrap();
|
|
|
|
- let sighash_arr = sighash_ctor();
|
|
|
|
- let sighash_tts: proc_macro2::TokenStream =
|
|
|
|
- format!("{:?}", sighash_arr).parse().unwrap();
|
|
|
|
- quote! {
|
|
|
|
- #sighash_tts => {
|
|
|
|
- let ix = instruction::#ix_name::deserialize(&mut instruction_data)
|
|
|
|
- .map_err(|_| ProgramError::Custom(1))?; // todo: error code
|
|
|
|
- let instruction::#variant_arm = ix;
|
|
|
|
- __private::__ctor(program_id, accounts, #(#ctor_args),*)
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- // Dispatch the state impl instructions.
|
|
|
|
- let state_dispatch_arms: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
|
|
- None => vec![],
|
|
|
|
- Some(s) => s
|
|
|
|
- .methods
|
|
|
|
- .iter()
|
|
|
|
- .map(|rpc: &crate::StateRpc| {
|
|
|
|
- let rpc_arg_names: Vec<&syn::Ident> =
|
|
|
|
- rpc.args.iter().map(|arg| &arg.name).collect();
|
|
|
|
- let name = &rpc.raw_method.sig.ident.to_string();
|
|
|
|
- let rpc_name: proc_macro2::TokenStream = { format!("__{}", name).parse().unwrap() };
|
|
|
|
- let variant_arm =
|
|
|
|
- generate_ix_variant(rpc.raw_method.sig.ident.to_string(), &rpc.args, true);
|
|
|
|
- let ix_name = generate_ix_variant_name(rpc.raw_method.sig.ident.to_string(), true);
|
|
|
|
- let sighash_arr = sighash(SIGHASH_STATE_NAMESPACE, &name);
|
|
|
|
|
|
+ Some(state) => match state.ctor_and_anchor.is_some() {
|
|
|
|
+ false => quote! {},
|
|
|
|
+ true => {
|
|
|
|
+ let variant_arm = generate_ctor_variant(state);
|
|
|
|
+ let ctor_args = generate_ctor_args(state);
|
|
|
|
+ let ix_name: proc_macro2::TokenStream =
|
|
|
|
+ generate_ctor_variant_name().parse().unwrap();
|
|
|
|
+ let sighash_arr = sighash_ctor();
|
|
let sighash_tts: proc_macro2::TokenStream =
|
|
let sighash_tts: proc_macro2::TokenStream =
|
|
format!("{:?}", sighash_arr).parse().unwrap();
|
|
format!("{:?}", sighash_arr).parse().unwrap();
|
|
quote! {
|
|
quote! {
|
|
@@ -109,66 +84,110 @@ pub fn generate_dispatch(program: &Program) -> proc_macro2::TokenStream {
|
|
let ix = instruction::#ix_name::deserialize(&mut instruction_data)
|
|
let ix = instruction::#ix_name::deserialize(&mut instruction_data)
|
|
.map_err(|_| ProgramError::Custom(1))?; // todo: error code
|
|
.map_err(|_| ProgramError::Custom(1))?; // todo: error code
|
|
let instruction::#variant_arm = ix;
|
|
let instruction::#variant_arm = ix;
|
|
- __private::#rpc_name(program_id, accounts, #(#rpc_arg_names),*)
|
|
|
|
|
|
+ __private::__ctor(program_id, accounts, #(#ctor_args),*)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- })
|
|
|
|
- .collect(),
|
|
|
|
|
|
+ }
|
|
|
|
+ },
|
|
};
|
|
};
|
|
|
|
|
|
- // Dispatch all trait interface implementations.
|
|
|
|
- let trait_dispatch_arms: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
|
|
|
|
+ // Dispatch the state impl instructions.
|
|
|
|
+ let state_dispatch_arms: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
None => vec![],
|
|
None => vec![],
|
|
Some(s) => s
|
|
Some(s) => s
|
|
- .interfaces
|
|
|
|
- .iter()
|
|
|
|
- .flat_map(|iface: &crate::StateInterface| {
|
|
|
|
- iface
|
|
|
|
- .methods
|
|
|
|
|
|
+ .impl_block_and_methods
|
|
|
|
+ .as_ref()
|
|
|
|
+ .map(|(_impl_block, methods)| {
|
|
|
|
+ methods
|
|
.iter()
|
|
.iter()
|
|
- .map(|m: &crate::StateRpc| {
|
|
|
|
|
|
+ .map(|rpc: &crate::StateRpc| {
|
|
let rpc_arg_names: Vec<&syn::Ident> =
|
|
let rpc_arg_names: Vec<&syn::Ident> =
|
|
- m.args.iter().map(|arg| &arg.name).collect();
|
|
|
|
- let name = &m.raw_method.sig.ident.to_string();
|
|
|
|
- let rpc_name: proc_macro2::TokenStream = format!("__{}_{}", iface.trait_name, name).parse().unwrap();
|
|
|
|
- let raw_args: Vec<&syn::PatType> = m
|
|
|
|
- .args
|
|
|
|
- .iter()
|
|
|
|
- .map(|arg: &crate::RpcArg| &arg.raw_arg)
|
|
|
|
- .collect();
|
|
|
|
- let sighash_arr = sighash(&iface.trait_name, &m.ident.to_string());
|
|
|
|
|
|
+ rpc.args.iter().map(|arg| &arg.name).collect();
|
|
|
|
+ let name = &rpc.raw_method.sig.ident.to_string();
|
|
|
|
+ let rpc_name: proc_macro2::TokenStream =
|
|
|
|
+ { format!("__{}", name).parse().unwrap() };
|
|
|
|
+ let variant_arm = generate_ix_variant(
|
|
|
|
+ rpc.raw_method.sig.ident.to_string(),
|
|
|
|
+ &rpc.args,
|
|
|
|
+ true,
|
|
|
|
+ );
|
|
|
|
+ let ix_name =
|
|
|
|
+ generate_ix_variant_name(rpc.raw_method.sig.ident.to_string(), true);
|
|
|
|
+ let sighash_arr = sighash(SIGHASH_STATE_NAMESPACE, &name);
|
|
let sighash_tts: proc_macro2::TokenStream =
|
|
let sighash_tts: proc_macro2::TokenStream =
|
|
format!("{:?}", sighash_arr).parse().unwrap();
|
|
format!("{:?}", sighash_arr).parse().unwrap();
|
|
- let args_struct = {
|
|
|
|
- if m.args.len() == 0 {
|
|
|
|
- quote! {
|
|
|
|
- #[derive(anchor_lang::AnchorSerialize, anchor_lang::AnchorDeserialize)]
|
|
|
|
- struct Args;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- quote! {
|
|
|
|
- #[derive(anchor_lang::AnchorSerialize, anchor_lang::AnchorDeserialize)]
|
|
|
|
- struct Args {
|
|
|
|
- #(#raw_args),*
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
quote! {
|
|
quote! {
|
|
#sighash_tts => {
|
|
#sighash_tts => {
|
|
- #args_struct
|
|
|
|
- let ix = Args::deserialize(&mut instruction_data)
|
|
|
|
|
|
+ let ix = instruction::#ix_name::deserialize(&mut instruction_data)
|
|
.map_err(|_| ProgramError::Custom(1))?; // todo: error code
|
|
.map_err(|_| ProgramError::Custom(1))?; // todo: error code
|
|
- let Args {
|
|
|
|
- #(#rpc_arg_names),*
|
|
|
|
- } = ix;
|
|
|
|
|
|
+ let instruction::#variant_arm = ix;
|
|
__private::#rpc_name(program_id, accounts, #(#rpc_arg_names),*)
|
|
__private::#rpc_name(program_id, accounts, #(#rpc_arg_names),*)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
})
|
|
- .collect::<Vec<proc_macro2::TokenStream>>()
|
|
|
|
|
|
+ .collect()
|
|
})
|
|
})
|
|
- .collect(),
|
|
|
|
|
|
+ .unwrap_or(vec![]),
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // Dispatch all trait interface implementations.
|
|
|
|
+ let trait_dispatch_arms: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
|
|
+ None => vec![],
|
|
|
|
+ Some(s) => s
|
|
|
|
+ .interfaces
|
|
|
|
+ .as_ref()
|
|
|
|
+ .map(|interfaces| {
|
|
|
|
+ interfaces
|
|
|
|
+ .iter()
|
|
|
|
+ .flat_map(|iface: &crate::StateInterface| {
|
|
|
|
+ iface
|
|
|
|
+ .methods
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|m: &crate::StateRpc| {
|
|
|
|
+ let rpc_arg_names: Vec<&syn::Ident> =
|
|
|
|
+ m.args.iter().map(|arg| &arg.name).collect();
|
|
|
|
+ let name = &m.raw_method.sig.ident.to_string();
|
|
|
|
+ let rpc_name: proc_macro2::TokenStream = format!("__{}_{}", iface.trait_name, name).parse().unwrap();
|
|
|
|
+ let raw_args: Vec<&syn::PatType> = m
|
|
|
|
+ .args
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|arg: &crate::RpcArg| &arg.raw_arg)
|
|
|
|
+ .collect();
|
|
|
|
+ let sighash_arr = sighash(&iface.trait_name, &m.ident.to_string());
|
|
|
|
+ let sighash_tts: proc_macro2::TokenStream =
|
|
|
|
+ format!("{:?}", sighash_arr).parse().unwrap();
|
|
|
|
+ let args_struct = {
|
|
|
|
+ if m.args.len() == 0 {
|
|
|
|
+ quote! {
|
|
|
|
+ #[derive(anchor_lang::AnchorSerialize, anchor_lang::AnchorDeserialize)]
|
|
|
|
+ struct Args;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ quote! {
|
|
|
|
+ #[derive(anchor_lang::AnchorSerialize, anchor_lang::AnchorDeserialize)]
|
|
|
|
+ struct Args {
|
|
|
|
+ #(#raw_args),*
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+ quote! {
|
|
|
|
+ #sighash_tts => {
|
|
|
|
+ #args_struct
|
|
|
|
+ let ix = Args::deserialize(&mut instruction_data)
|
|
|
|
+ .map_err(|_| ProgramError::Custom(1))?; // todo: error code
|
|
|
|
+ let Args {
|
|
|
|
+ #(#rpc_arg_names),*
|
|
|
|
+ } = ix;
|
|
|
|
+ __private::#rpc_name(program_id, accounts, #(#rpc_arg_names),*)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ .collect::<Vec<proc_macro2::TokenStream>>()
|
|
|
|
+ })
|
|
|
|
+ .collect()
|
|
|
|
+ })
|
|
|
|
+ .unwrap_or(vec![])
|
|
};
|
|
};
|
|
|
|
|
|
// Dispatch all global instructions.
|
|
// Dispatch all global instructions.
|
|
@@ -346,234 +365,246 @@ pub fn generate_non_inlined_handlers(program: &Program) -> proc_macro2::TokenStr
|
|
};
|
|
};
|
|
let non_inlined_ctor: proc_macro2::TokenStream = match &program.state {
|
|
let non_inlined_ctor: proc_macro2::TokenStream = match &program.state {
|
|
None => quote! {},
|
|
None => quote! {},
|
|
- Some(state) => {
|
|
|
|
- let ctor_typed_args = generate_ctor_typed_args(state);
|
|
|
|
- let ctor_untyped_args = generate_ctor_args(state);
|
|
|
|
- let name = &state.strct.ident;
|
|
|
|
- let mod_name = &program.name;
|
|
|
|
- let anchor_ident = &state.ctor_anchor;
|
|
|
|
- quote! {
|
|
|
|
- // One time state account initializer. Will faill on subsequent
|
|
|
|
- // invocations.
|
|
|
|
- #[inline(never)]
|
|
|
|
- pub fn __ctor(program_id: &Pubkey, accounts: &[AccountInfo], #(#ctor_typed_args),*) -> ProgramResult {
|
|
|
|
- let mut remaining_accounts: &[AccountInfo] = accounts;
|
|
|
|
-
|
|
|
|
- // Deserialize accounts.
|
|
|
|
- let ctor_accounts = anchor_lang::Ctor::try_accounts(program_id, &mut remaining_accounts)?;
|
|
|
|
- let mut ctor_user_def_accounts = #anchor_ident::try_accounts(program_id, &mut remaining_accounts)?;
|
|
|
|
-
|
|
|
|
- // Invoke the ctor.
|
|
|
|
- let instance = #mod_name::#name::new(
|
|
|
|
- anchor_lang::Context::new(
|
|
|
|
- program_id,
|
|
|
|
- &mut ctor_user_def_accounts,
|
|
|
|
- remaining_accounts,
|
|
|
|
- ),
|
|
|
|
- #(#ctor_untyped_args),*
|
|
|
|
- )?;
|
|
|
|
-
|
|
|
|
- // Create the solana account for the ctor data.
|
|
|
|
- let from = ctor_accounts.from.key;
|
|
|
|
- let (base, nonce) = Pubkey::find_program_address(&[], ctor_accounts.program.key);
|
|
|
|
- let seed = anchor_lang::ProgramState::<#name>::seed();
|
|
|
|
- let owner = ctor_accounts.program.key;
|
|
|
|
- let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
|
|
|
|
- // Add 8 for the account discriminator.
|
|
|
|
- let space = 8 + instance.try_to_vec().map_err(|_| ProgramError::Custom(1))?.len();
|
|
|
|
- let lamports = ctor_accounts.rent.minimum_balance(space);
|
|
|
|
- let seeds = &[&[nonce][..]];
|
|
|
|
- let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed(
|
|
|
|
- from,
|
|
|
|
- &to,
|
|
|
|
- &base,
|
|
|
|
- seed,
|
|
|
|
- lamports,
|
|
|
|
- space as u64,
|
|
|
|
- owner,
|
|
|
|
- );
|
|
|
|
- anchor_lang::solana_program::program::invoke_signed(
|
|
|
|
- &ix,
|
|
|
|
- &[
|
|
|
|
- ctor_accounts.from.clone(),
|
|
|
|
- ctor_accounts.to.clone(),
|
|
|
|
- ctor_accounts.base.clone(),
|
|
|
|
- ctor_accounts.system_program.clone(),
|
|
|
|
- ],
|
|
|
|
- &[seeds],
|
|
|
|
- )?;
|
|
|
|
-
|
|
|
|
- // Serialize the state and save it to storage.
|
|
|
|
- ctor_user_def_accounts.exit(program_id)?;
|
|
|
|
- let mut data = ctor_accounts.to.try_borrow_mut_data()?;
|
|
|
|
- let dst: &mut [u8] = &mut data;
|
|
|
|
- let mut cursor = std::io::Cursor::new(dst);
|
|
|
|
- instance.try_serialize(&mut cursor)?;
|
|
|
|
-
|
|
|
|
- Ok(())
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
- let non_inlined_state_handlers: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
|
|
- None => vec![],
|
|
|
|
- Some(state) => state
|
|
|
|
- .methods
|
|
|
|
- .iter()
|
|
|
|
- .map(|rpc| {
|
|
|
|
- let rpc_params: Vec<_> = rpc.args.iter().map(|arg| &arg.raw_arg).collect();
|
|
|
|
- let rpc_arg_names: Vec<&syn::Ident> =
|
|
|
|
- rpc.args.iter().map(|arg| &arg.name).collect();
|
|
|
|
- let private_rpc_name: proc_macro2::TokenStream = {
|
|
|
|
- let n = format!("__{}", &rpc.raw_method.sig.ident.to_string());
|
|
|
|
- n.parse().unwrap()
|
|
|
|
- };
|
|
|
|
- let rpc_name = &rpc.raw_method.sig.ident;
|
|
|
|
- let state_ty: proc_macro2::TokenStream = state.name.parse().unwrap();
|
|
|
|
- let anchor_ident = &rpc.anchor_ident;
|
|
|
|
|
|
+ Some(state) => match state.ctor_and_anchor.as_ref() {
|
|
|
|
+ None => quote! {},
|
|
|
|
+ Some((_ctor, anchor_ident)) => {
|
|
|
|
+ let ctor_typed_args = generate_ctor_typed_args(state);
|
|
|
|
+ let ctor_untyped_args = generate_ctor_args(state);
|
|
|
|
+ let name = &state.strct.ident;
|
|
|
|
+ let mod_name = &program.name;
|
|
quote! {
|
|
quote! {
|
|
|
|
+ // One time state account initializer. Will faill on subsequent
|
|
|
|
+ // invocations.
|
|
#[inline(never)]
|
|
#[inline(never)]
|
|
- pub fn #private_rpc_name(
|
|
|
|
- program_id: &Pubkey,
|
|
|
|
- accounts: &[AccountInfo],
|
|
|
|
- #(#rpc_params),*
|
|
|
|
- ) -> ProgramResult {
|
|
|
|
-
|
|
|
|
|
|
+ pub fn __ctor(program_id: &Pubkey, accounts: &[AccountInfo], #(#ctor_typed_args),*) -> ProgramResult {
|
|
let mut remaining_accounts: &[AccountInfo] = accounts;
|
|
let mut remaining_accounts: &[AccountInfo] = accounts;
|
|
- if remaining_accounts.len() == 0 {
|
|
|
|
- return Err(ProgramError::Custom(1)); // todo
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Deserialize the program state account.
|
|
|
|
- let state_account = &remaining_accounts[0];
|
|
|
|
- let mut state: #state_ty = {
|
|
|
|
- let data = state_account.try_borrow_data()?;
|
|
|
|
- let mut sliced: &[u8] = &data;
|
|
|
|
- anchor_lang::AccountDeserialize::try_deserialize(&mut sliced)?
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- remaining_accounts = &remaining_accounts[1..];
|
|
|
|
|
|
|
|
- // Deserialize the program's execution context.
|
|
|
|
- let mut accounts = #anchor_ident::try_accounts(
|
|
|
|
- program_id,
|
|
|
|
- &mut remaining_accounts,
|
|
|
|
|
|
+ // Deserialize accounts.
|
|
|
|
+ let ctor_accounts = anchor_lang::Ctor::try_accounts(program_id, &mut remaining_accounts)?;
|
|
|
|
+ let mut ctor_user_def_accounts = #anchor_ident::try_accounts(program_id, &mut remaining_accounts)?;
|
|
|
|
+
|
|
|
|
+ // Invoke the ctor.
|
|
|
|
+ let instance = #mod_name::#name::new(
|
|
|
|
+ anchor_lang::Context::new(
|
|
|
|
+ program_id,
|
|
|
|
+ &mut ctor_user_def_accounts,
|
|
|
|
+ remaining_accounts,
|
|
|
|
+ ),
|
|
|
|
+ #(#ctor_untyped_args),*
|
|
)?;
|
|
)?;
|
|
- let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
|
|
|
|
|
|
|
|
- // Execute user defined function.
|
|
|
|
- state.#rpc_name(
|
|
|
|
- ctx,
|
|
|
|
- #(#rpc_arg_names),*
|
|
|
|
|
|
+ // Create the solana account for the ctor data.
|
|
|
|
+ let from = ctor_accounts.from.key;
|
|
|
|
+ let (base, nonce) = Pubkey::find_program_address(&[], ctor_accounts.program.key);
|
|
|
|
+ let seed = anchor_lang::ProgramState::<#name>::seed();
|
|
|
|
+ let owner = ctor_accounts.program.key;
|
|
|
|
+ let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
|
|
|
|
+ // Add 8 for the account discriminator.
|
|
|
|
+ let space = 8 + instance.try_to_vec().map_err(|_| ProgramError::Custom(1))?.len();
|
|
|
|
+ let lamports = ctor_accounts.rent.minimum_balance(space);
|
|
|
|
+ let seeds = &[&[nonce][..]];
|
|
|
|
+ let ix = anchor_lang::solana_program::system_instruction::create_account_with_seed(
|
|
|
|
+ from,
|
|
|
|
+ &to,
|
|
|
|
+ &base,
|
|
|
|
+ seed,
|
|
|
|
+ lamports,
|
|
|
|
+ space as u64,
|
|
|
|
+ owner,
|
|
|
|
+ );
|
|
|
|
+ anchor_lang::solana_program::program::invoke_signed(
|
|
|
|
+ &ix,
|
|
|
|
+ &[
|
|
|
|
+ ctor_accounts.from.clone(),
|
|
|
|
+ ctor_accounts.to.clone(),
|
|
|
|
+ ctor_accounts.base.clone(),
|
|
|
|
+ ctor_accounts.system_program.clone(),
|
|
|
|
+ ],
|
|
|
|
+ &[seeds],
|
|
)?;
|
|
)?;
|
|
|
|
|
|
// Serialize the state and save it to storage.
|
|
// Serialize the state and save it to storage.
|
|
- accounts.exit(program_id)?;
|
|
|
|
- let mut data = state_account.try_borrow_mut_data()?;
|
|
|
|
|
|
+ ctor_user_def_accounts.exit(program_id)?;
|
|
|
|
+ let mut data = ctor_accounts.to.try_borrow_mut_data()?;
|
|
let dst: &mut [u8] = &mut data;
|
|
let dst: &mut [u8] = &mut data;
|
|
let mut cursor = std::io::Cursor::new(dst);
|
|
let mut cursor = std::io::Cursor::new(dst);
|
|
- state.try_serialize(&mut cursor)?;
|
|
|
|
|
|
+ instance.try_serialize(&mut cursor)?;
|
|
|
|
|
|
Ok(())
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- })
|
|
|
|
- .collect(),
|
|
|
|
|
|
+ }
|
|
|
|
+ },
|
|
};
|
|
};
|
|
- let non_inlined_state_trait_handlers: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
|
|
- None => Vec::new(),
|
|
|
|
|
|
+ let non_inlined_state_handlers: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
|
|
+ None => vec![],
|
|
Some(state) => state
|
|
Some(state) => state
|
|
- .interfaces
|
|
|
|
- .iter()
|
|
|
|
- .flat_map(|iface: &crate::StateInterface| {
|
|
|
|
- iface
|
|
|
|
- .methods
|
|
|
|
|
|
+ .impl_block_and_methods
|
|
|
|
+ .as_ref()
|
|
|
|
+ .map(|(_impl_block, methods)| {
|
|
|
|
+ methods
|
|
.iter()
|
|
.iter()
|
|
.map(|rpc| {
|
|
.map(|rpc| {
|
|
let rpc_params: Vec<_> = rpc.args.iter().map(|arg| &arg.raw_arg).collect();
|
|
let rpc_params: Vec<_> = rpc.args.iter().map(|arg| &arg.raw_arg).collect();
|
|
let rpc_arg_names: Vec<&syn::Ident> =
|
|
let rpc_arg_names: Vec<&syn::Ident> =
|
|
rpc.args.iter().map(|arg| &arg.name).collect();
|
|
rpc.args.iter().map(|arg| &arg.name).collect();
|
|
let private_rpc_name: proc_macro2::TokenStream = {
|
|
let private_rpc_name: proc_macro2::TokenStream = {
|
|
- let n = format!("__{}_{}", iface.trait_name, &rpc.raw_method.sig.ident.to_string());
|
|
|
|
|
|
+ let n = format!("__{}", &rpc.raw_method.sig.ident.to_string());
|
|
n.parse().unwrap()
|
|
n.parse().unwrap()
|
|
};
|
|
};
|
|
let rpc_name = &rpc.raw_method.sig.ident;
|
|
let rpc_name = &rpc.raw_method.sig.ident;
|
|
let state_ty: proc_macro2::TokenStream = state.name.parse().unwrap();
|
|
let state_ty: proc_macro2::TokenStream = state.name.parse().unwrap();
|
|
let anchor_ident = &rpc.anchor_ident;
|
|
let anchor_ident = &rpc.anchor_ident;
|
|
|
|
+ quote! {
|
|
|
|
+ #[inline(never)]
|
|
|
|
+ pub fn #private_rpc_name(
|
|
|
|
+ program_id: &Pubkey,
|
|
|
|
+ accounts: &[AccountInfo],
|
|
|
|
+ #(#rpc_params),*
|
|
|
|
+ ) -> ProgramResult {
|
|
|
|
+
|
|
|
|
+ let mut remaining_accounts: &[AccountInfo] = accounts;
|
|
|
|
+ if remaining_accounts.len() == 0 {
|
|
|
|
+ return Err(ProgramError::Custom(1)); // todo
|
|
|
|
+ }
|
|
|
|
|
|
- if rpc.has_receiver {
|
|
|
|
- quote! {
|
|
|
|
- #[inline(never)]
|
|
|
|
- pub fn #private_rpc_name(
|
|
|
|
- program_id: &Pubkey,
|
|
|
|
- accounts: &[AccountInfo],
|
|
|
|
- #(#rpc_params),*
|
|
|
|
- ) -> ProgramResult {
|
|
|
|
-
|
|
|
|
- let mut remaining_accounts: &[AccountInfo] = accounts;
|
|
|
|
- if remaining_accounts.len() == 0 {
|
|
|
|
- return Err(ProgramError::Custom(1)); // todo
|
|
|
|
- }
|
|
|
|
|
|
+ // Deserialize the program state account.
|
|
|
|
+ let state_account = &remaining_accounts[0];
|
|
|
|
+ let mut state: #state_ty = {
|
|
|
|
+ let data = state_account.try_borrow_data()?;
|
|
|
|
+ let mut sliced: &[u8] = &data;
|
|
|
|
+ anchor_lang::AccountDeserialize::try_deserialize(&mut sliced)?
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ remaining_accounts = &remaining_accounts[1..];
|
|
|
|
+
|
|
|
|
+ // Deserialize the program's execution context.
|
|
|
|
+ let mut accounts = #anchor_ident::try_accounts(
|
|
|
|
+ program_id,
|
|
|
|
+ &mut remaining_accounts,
|
|
|
|
+ )?;
|
|
|
|
+ let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
|
|
|
|
+
|
|
|
|
+ // Execute user defined function.
|
|
|
|
+ state.#rpc_name(
|
|
|
|
+ ctx,
|
|
|
|
+ #(#rpc_arg_names),*
|
|
|
|
+ )?;
|
|
|
|
|
|
- // Deserialize the program state account.
|
|
|
|
- let state_account = &remaining_accounts[0];
|
|
|
|
- let mut state: #state_ty = {
|
|
|
|
- let data = state_account.try_borrow_data()?;
|
|
|
|
- let mut sliced: &[u8] = &data;
|
|
|
|
- anchor_lang::AccountDeserialize::try_deserialize(&mut sliced)?
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- remaining_accounts = &remaining_accounts[1..];
|
|
|
|
-
|
|
|
|
- // Deserialize the program's execution context.
|
|
|
|
- let mut accounts = #anchor_ident::try_accounts(
|
|
|
|
- program_id,
|
|
|
|
- &mut remaining_accounts,
|
|
|
|
- )?;
|
|
|
|
- let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
|
|
|
|
-
|
|
|
|
- // Execute user defined function.
|
|
|
|
- state.#rpc_name(
|
|
|
|
- ctx,
|
|
|
|
- #(#rpc_arg_names),*
|
|
|
|
- )?;
|
|
|
|
-
|
|
|
|
- // Serialize the state and save it to storage.
|
|
|
|
- accounts.exit(program_id)?;
|
|
|
|
- let mut data = state_account.try_borrow_mut_data()?;
|
|
|
|
- let dst: &mut [u8] = &mut data;
|
|
|
|
- let mut cursor = std::io::Cursor::new(dst);
|
|
|
|
- state.try_serialize(&mut cursor)?;
|
|
|
|
-
|
|
|
|
- Ok(())
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- let state_name: proc_macro2::TokenStream = state.name.parse().unwrap();
|
|
|
|
- quote! {
|
|
|
|
- #[inline(never)]
|
|
|
|
- pub fn #private_rpc_name(
|
|
|
|
- program_id: &Pubkey,
|
|
|
|
- accounts: &[AccountInfo],
|
|
|
|
- #(#rpc_params),*
|
|
|
|
- ) -> ProgramResult {
|
|
|
|
- let mut remaining_accounts: &[AccountInfo] = accounts;
|
|
|
|
- let mut accounts = #anchor_ident::try_accounts(
|
|
|
|
- program_id,
|
|
|
|
- &mut remaining_accounts,
|
|
|
|
- )?;
|
|
|
|
- #state_name::#rpc_name(
|
|
|
|
- Context::new(program_id, &mut accounts, remaining_accounts),
|
|
|
|
- #(#rpc_arg_names),*
|
|
|
|
- )?;
|
|
|
|
- accounts.exit(program_id)
|
|
|
|
- }
|
|
|
|
|
|
+ // Serialize the state and save it to storage.
|
|
|
|
+ accounts.exit(program_id)?;
|
|
|
|
+ let mut data = state_account.try_borrow_mut_data()?;
|
|
|
|
+ let dst: &mut [u8] = &mut data;
|
|
|
|
+ let mut cursor = std::io::Cursor::new(dst);
|
|
|
|
+ state.try_serialize(&mut cursor)?;
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
})
|
|
- .collect::<Vec<proc_macro2::TokenStream>>()
|
|
|
|
|
|
+ .collect()
|
|
})
|
|
})
|
|
- .collect(),
|
|
|
|
|
|
+ .unwrap_or(vec![]),
|
|
|
|
+ };
|
|
|
|
+ let non_inlined_state_trait_handlers: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
|
|
+ None => Vec::new(),
|
|
|
|
+ Some(state) => state
|
|
|
|
+ .interfaces
|
|
|
|
+ .as_ref()
|
|
|
|
+ .map(|interfaces| {
|
|
|
|
+ interfaces
|
|
|
|
+ .iter()
|
|
|
|
+ .flat_map(|iface: &crate::StateInterface| {
|
|
|
|
+ iface
|
|
|
|
+ .methods
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|rpc| {
|
|
|
|
+ let rpc_params: Vec<_> = rpc.args.iter().map(|arg| &arg.raw_arg).collect();
|
|
|
|
+ let rpc_arg_names: Vec<&syn::Ident> =
|
|
|
|
+ rpc.args.iter().map(|arg| &arg.name).collect();
|
|
|
|
+ let private_rpc_name: proc_macro2::TokenStream = {
|
|
|
|
+ let n = format!("__{}_{}", iface.trait_name, &rpc.raw_method.sig.ident.to_string());
|
|
|
|
+ n.parse().unwrap()
|
|
|
|
+ };
|
|
|
|
+ let rpc_name = &rpc.raw_method.sig.ident;
|
|
|
|
+ let state_ty: proc_macro2::TokenStream = state.name.parse().unwrap();
|
|
|
|
+ let anchor_ident = &rpc.anchor_ident;
|
|
|
|
+
|
|
|
|
+ if rpc.has_receiver {
|
|
|
|
+ quote! {
|
|
|
|
+ #[inline(never)]
|
|
|
|
+ pub fn #private_rpc_name(
|
|
|
|
+ program_id: &Pubkey,
|
|
|
|
+ accounts: &[AccountInfo],
|
|
|
|
+ #(#rpc_params),*
|
|
|
|
+ ) -> ProgramResult {
|
|
|
|
+
|
|
|
|
+ let mut remaining_accounts: &[AccountInfo] = accounts;
|
|
|
|
+ if remaining_accounts.len() == 0 {
|
|
|
|
+ return Err(ProgramError::Custom(1)); // todo
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Deserialize the program state account.
|
|
|
|
+ let state_account = &remaining_accounts[0];
|
|
|
|
+ let mut state: #state_ty = {
|
|
|
|
+ let data = state_account.try_borrow_data()?;
|
|
|
|
+ let mut sliced: &[u8] = &data;
|
|
|
|
+ anchor_lang::AccountDeserialize::try_deserialize(&mut sliced)?
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ remaining_accounts = &remaining_accounts[1..];
|
|
|
|
+
|
|
|
|
+ // Deserialize the program's execution context.
|
|
|
|
+ let mut accounts = #anchor_ident::try_accounts(
|
|
|
|
+ program_id,
|
|
|
|
+ &mut remaining_accounts,
|
|
|
|
+ )?;
|
|
|
|
+ let ctx = Context::new(program_id, &mut accounts, remaining_accounts);
|
|
|
|
+
|
|
|
|
+ // Execute user defined function.
|
|
|
|
+ state.#rpc_name(
|
|
|
|
+ ctx,
|
|
|
|
+ #(#rpc_arg_names),*
|
|
|
|
+ )?;
|
|
|
|
+
|
|
|
|
+ // Serialize the state and save it to storage.
|
|
|
|
+ accounts.exit(program_id)?;
|
|
|
|
+ let mut data = state_account.try_borrow_mut_data()?;
|
|
|
|
+ let dst: &mut [u8] = &mut data;
|
|
|
|
+ let mut cursor = std::io::Cursor::new(dst);
|
|
|
|
+ state.try_serialize(&mut cursor)?;
|
|
|
|
+
|
|
|
|
+ Ok(())
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ let state_name: proc_macro2::TokenStream = state.name.parse().unwrap();
|
|
|
|
+ quote! {
|
|
|
|
+ #[inline(never)]
|
|
|
|
+ pub fn #private_rpc_name(
|
|
|
|
+ program_id: &Pubkey,
|
|
|
|
+ accounts: &[AccountInfo],
|
|
|
|
+ #(#rpc_params),*
|
|
|
|
+ ) -> ProgramResult {
|
|
|
|
+ let mut remaining_accounts: &[AccountInfo] = accounts;
|
|
|
|
+ let mut accounts = #anchor_ident::try_accounts(
|
|
|
|
+ program_id,
|
|
|
|
+ &mut remaining_accounts,
|
|
|
|
+ )?;
|
|
|
|
+ #state_name::#rpc_name(
|
|
|
|
+ Context::new(program_id, &mut accounts, remaining_accounts),
|
|
|
|
+ #(#rpc_arg_names),*
|
|
|
|
+ )?;
|
|
|
|
+ accounts.exit(program_id)
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ .collect::<Vec<proc_macro2::TokenStream>>()
|
|
|
|
+ })
|
|
|
|
+ .collect()
|
|
|
|
+ })
|
|
|
|
+ .unwrap_or(Vec::new()),
|
|
};
|
|
};
|
|
let non_inlined_handlers: Vec<proc_macro2::TokenStream> = program
|
|
let non_inlined_handlers: Vec<proc_macro2::TokenStream> = program
|
|
.rpcs
|
|
.rpcs
|
|
@@ -663,42 +694,50 @@ pub fn generate_ctor_typed_variant_with_semi(program: &Program) -> proc_macro2::
|
|
|
|
|
|
fn generate_ctor_typed_args(state: &State) -> Vec<syn::PatType> {
|
|
fn generate_ctor_typed_args(state: &State) -> Vec<syn::PatType> {
|
|
state
|
|
state
|
|
- .ctor
|
|
|
|
- .sig
|
|
|
|
- .inputs
|
|
|
|
- .iter()
|
|
|
|
- .filter_map(|arg: &syn::FnArg| match arg {
|
|
|
|
- syn::FnArg::Typed(pat_ty) => {
|
|
|
|
- let mut arg_str = parser::tts_to_string(&pat_ty.ty);
|
|
|
|
- arg_str.retain(|c| !c.is_whitespace());
|
|
|
|
- if arg_str.starts_with("Context<") {
|
|
|
|
- return None;
|
|
|
|
- }
|
|
|
|
- Some(pat_ty.clone())
|
|
|
|
- }
|
|
|
|
- _ => panic!("Invalid syntaxe,"),
|
|
|
|
|
|
+ .ctor_and_anchor
|
|
|
|
+ .as_ref()
|
|
|
|
+ .map(|(ctor, _anchor_ident)| {
|
|
|
|
+ ctor.sig
|
|
|
|
+ .inputs
|
|
|
|
+ .iter()
|
|
|
|
+ .filter_map(|arg: &syn::FnArg| match arg {
|
|
|
|
+ syn::FnArg::Typed(pat_ty) => {
|
|
|
|
+ let mut arg_str = parser::tts_to_string(&pat_ty.ty);
|
|
|
|
+ arg_str.retain(|c| !c.is_whitespace());
|
|
|
|
+ if arg_str.starts_with("Context<") {
|
|
|
|
+ return None;
|
|
|
|
+ }
|
|
|
|
+ Some(pat_ty.clone())
|
|
|
|
+ }
|
|
|
|
+ _ => panic!("Invalid syntaxe,"),
|
|
|
|
+ })
|
|
|
|
+ .collect()
|
|
})
|
|
})
|
|
- .collect()
|
|
|
|
|
|
+ .unwrap_or(Vec::new())
|
|
}
|
|
}
|
|
|
|
|
|
fn generate_ctor_args(state: &State) -> Vec<Box<syn::Pat>> {
|
|
fn generate_ctor_args(state: &State) -> Vec<Box<syn::Pat>> {
|
|
state
|
|
state
|
|
- .ctor
|
|
|
|
- .sig
|
|
|
|
- .inputs
|
|
|
|
- .iter()
|
|
|
|
- .filter_map(|arg: &syn::FnArg| match arg {
|
|
|
|
- syn::FnArg::Typed(pat_ty) => {
|
|
|
|
- let mut arg_str = parser::tts_to_string(&pat_ty.ty);
|
|
|
|
- arg_str.retain(|c| !c.is_whitespace());
|
|
|
|
- if arg_str.starts_with("Context<") {
|
|
|
|
- return None;
|
|
|
|
- }
|
|
|
|
- Some(pat_ty.pat.clone())
|
|
|
|
- }
|
|
|
|
- _ => panic!(""),
|
|
|
|
|
|
+ .ctor_and_anchor
|
|
|
|
+ .as_ref()
|
|
|
|
+ .map(|(ctor, _anchor_ident)| {
|
|
|
|
+ ctor.sig
|
|
|
|
+ .inputs
|
|
|
|
+ .iter()
|
|
|
|
+ .filter_map(|arg: &syn::FnArg| match arg {
|
|
|
|
+ syn::FnArg::Typed(pat_ty) => {
|
|
|
|
+ let mut arg_str = parser::tts_to_string(&pat_ty.ty);
|
|
|
|
+ arg_str.retain(|c| !c.is_whitespace());
|
|
|
|
+ if arg_str.starts_with("Context<") {
|
|
|
|
+ return None;
|
|
|
|
+ }
|
|
|
|
+ Some(pat_ty.pat.clone())
|
|
|
|
+ }
|
|
|
|
+ _ => panic!(""),
|
|
|
|
+ })
|
|
|
|
+ .collect()
|
|
})
|
|
})
|
|
- .collect()
|
|
|
|
|
|
+ .unwrap_or(Vec::new())
|
|
}
|
|
}
|
|
|
|
|
|
pub fn generate_ix_variant(
|
|
pub fn generate_ix_variant(
|
|
@@ -750,62 +789,67 @@ pub fn generate_instructions(program: &Program) -> proc_macro2::TokenStream {
|
|
let state_method_variants: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
let state_method_variants: Vec<proc_macro2::TokenStream> = match &program.state {
|
|
None => vec![],
|
|
None => vec![],
|
|
Some(state) => state
|
|
Some(state) => state
|
|
- .methods
|
|
|
|
- .iter()
|
|
|
|
- .map(|method| {
|
|
|
|
- let rpc_name_camel: proc_macro2::TokenStream = {
|
|
|
|
- let name = format!(
|
|
|
|
- "__{}",
|
|
|
|
- &method.raw_method.sig.ident.to_string().to_camel_case(),
|
|
|
|
- );
|
|
|
|
- name.parse().unwrap()
|
|
|
|
- };
|
|
|
|
- let raw_args: Vec<proc_macro2::TokenStream> = method
|
|
|
|
- .args
|
|
|
|
|
|
+ .impl_block_and_methods
|
|
|
|
+ .as_ref()
|
|
|
|
+ .map(|(_impl_block, methods)| {
|
|
|
|
+ methods
|
|
.iter()
|
|
.iter()
|
|
- .map(|arg| {
|
|
|
|
- format!("pub {}", parser::tts_to_string(&arg.raw_arg))
|
|
|
|
- .parse()
|
|
|
|
- .unwrap()
|
|
|
|
- })
|
|
|
|
- .collect();
|
|
|
|
-
|
|
|
|
- let ix_data_trait = {
|
|
|
|
- let name = method.raw_method.sig.ident.to_string();
|
|
|
|
- let sighash_arr = sighash(SIGHASH_GLOBAL_NAMESPACE, &name);
|
|
|
|
- let sighash_tts: proc_macro2::TokenStream =
|
|
|
|
- format!("{:?}", sighash_arr).parse().unwrap();
|
|
|
|
- quote! {
|
|
|
|
- impl anchor_lang::InstructionData for #rpc_name_camel {
|
|
|
|
- fn data(&self) -> Vec<u8> {
|
|
|
|
- let mut d = #sighash_tts.to_vec();
|
|
|
|
- d.append(&mut self.try_to_vec().expect("Should always serialize"));
|
|
|
|
- d
|
|
|
|
|
|
+ .map(|method| {
|
|
|
|
+ let rpc_name_camel: proc_macro2::TokenStream = {
|
|
|
|
+ let name = format!(
|
|
|
|
+ "__{}",
|
|
|
|
+ &method.raw_method.sig.ident.to_string().to_camel_case(),
|
|
|
|
+ );
|
|
|
|
+ name.parse().unwrap()
|
|
|
|
+ };
|
|
|
|
+ let raw_args: Vec<proc_macro2::TokenStream> = method
|
|
|
|
+ .args
|
|
|
|
+ .iter()
|
|
|
|
+ .map(|arg| {
|
|
|
|
+ format!("pub {}", parser::tts_to_string(&arg.raw_arg))
|
|
|
|
+ .parse()
|
|
|
|
+ .unwrap()
|
|
|
|
+ })
|
|
|
|
+ .collect();
|
|
|
|
+
|
|
|
|
+ let ix_data_trait = {
|
|
|
|
+ let name = method.raw_method.sig.ident.to_string();
|
|
|
|
+ let sighash_arr = sighash(SIGHASH_GLOBAL_NAMESPACE, &name);
|
|
|
|
+ let sighash_tts: proc_macro2::TokenStream =
|
|
|
|
+ format!("{:?}", sighash_arr).parse().unwrap();
|
|
|
|
+ quote! {
|
|
|
|
+ impl anchor_lang::InstructionData for #rpc_name_camel {
|
|
|
|
+ fn data(&self) -> Vec<u8> {
|
|
|
|
+ let mut d = #sighash_tts.to_vec();
|
|
|
|
+ d.append(&mut self.try_to_vec().expect("Should always serialize"));
|
|
|
|
+ d
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
|
|
+ };
|
|
|
|
|
|
- // If no args, output a "unit" variant instead of a struct variant.
|
|
|
|
- if method.args.len() == 0 {
|
|
|
|
- quote! {
|
|
|
|
- #[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
|
- pub struct #rpc_name_camel;
|
|
|
|
|
|
+ // If no args, output a "unit" variant instead of a struct variant.
|
|
|
|
+ if method.args.len() == 0 {
|
|
|
|
+ quote! {
|
|
|
|
+ #[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
|
+ pub struct #rpc_name_camel;
|
|
|
|
|
|
- #ix_data_trait
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- quote! {
|
|
|
|
- #[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
|
- pub struct #rpc_name_camel {
|
|
|
|
- #(#raw_args),*
|
|
|
|
- }
|
|
|
|
|
|
+ #ix_data_trait
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ quote! {
|
|
|
|
+ #[derive(AnchorSerialize, AnchorDeserialize)]
|
|
|
|
+ pub struct #rpc_name_camel {
|
|
|
|
+ #(#raw_args),*
|
|
|
|
+ }
|
|
|
|
|
|
- #ix_data_trait
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ #ix_data_trait
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ .collect()
|
|
})
|
|
})
|
|
- .collect(),
|
|
|
|
|
|
+ .unwrap_or(Vec::new()),
|
|
};
|
|
};
|
|
let variants: Vec<proc_macro2::TokenStream> = program
|
|
let variants: Vec<proc_macro2::TokenStream> = program
|
|
.rpcs
|
|
.rpcs
|
|
@@ -876,16 +920,18 @@ pub fn generate_instructions(program: &Program) -> proc_macro2::TokenStream {
|
|
fn generate_accounts(program: &Program) -> proc_macro2::TokenStream {
|
|
fn generate_accounts(program: &Program) -> proc_macro2::TokenStream {
|
|
let mut accounts = std::collections::HashSet::new();
|
|
let mut accounts = std::collections::HashSet::new();
|
|
|
|
|
|
- // Got through state accounts.
|
|
|
|
|
|
+ // Go through state accounts.
|
|
if let Some(state) = &program.state {
|
|
if let Some(state) = &program.state {
|
|
- for rpc in &state.methods {
|
|
|
|
- let anchor_ident = &rpc.anchor_ident;
|
|
|
|
- // TODO: move to fn and share with accounts.rs.
|
|
|
|
- let macro_name = format!(
|
|
|
|
- "__client_accounts_{}",
|
|
|
|
- anchor_ident.to_string().to_snake_case()
|
|
|
|
- );
|
|
|
|
- accounts.insert(macro_name);
|
|
|
|
|
|
+ if let Some((_impl_block, methods)) = &state.impl_block_and_methods {
|
|
|
|
+ for rpc in methods {
|
|
|
|
+ let anchor_ident = &rpc.anchor_ident;
|
|
|
|
+ // TODO: move to fn and share with accounts.rs.
|
|
|
|
+ let macro_name = format!(
|
|
|
|
+ "__client_accounts_{}",
|
|
|
|
+ anchor_ident.to_string().to_snake_case()
|
|
|
|
+ );
|
|
|
|
+ accounts.insert(macro_name);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|