sanctum_macros/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use create_with_seed::CreateWithSeedArgs;
4use proc_macro::TokenStream;
5use quote::{format_ident, quote};
6use syn::parse_macro_input;
7
8mod create_with_seed;
9mod declare_program_keys;
10mod utils;
11
12use declare_program_keys::{static_pda_gen, DeclareProgramKeysArgs};
13use utils::{gen_pubkey_consts, gen_pubkey_consts_with_litstr};
14
15// All #[proc_macro] s must reside at root of crate.
16// Signature is (input: proc_macro::TokenStream) -> proc_macro::TokenStream
17// NOT proc_macro2
18
19/// Declare a program ID with static PDAs.
20///
21/// Example:
22///
23/// ```rust
24/// // first arg = program ID
25/// // second arg = list of static PDA names and their seeds.
26/// //
27/// // Rules from solana runtime:
28/// // - Each seed can have a max length of 32 bytes.
29/// // - Each PDA can have max 16 seeds.
30/// sanctum_macros::declare_program_keys!(
31///     "9BoN4yBYwH63LFM9fDamaHK62YjM56hWYZqok7MnAakJ",
32///     [
33///         ("state", b"state"),
34///         ("empty-kebab", b""),
35///         ("multiseed", b"two", b"seeds"),
36///     ]
37/// );
38/// ```
39#[proc_macro]
40pub fn declare_program_keys(input: TokenStream) -> TokenStream {
41    let DeclareProgramKeysArgs {
42        prog_id_lit_str,
43        prog_id,
44        static_pdas,
45    } = parse_macro_input!(input);
46    // everything below must be infallible
47    let id_consts = gen_pubkey_consts_with_litstr("", prog_id, prog_id_lit_str);
48    let mut res = quote! {
49        #id_consts
50    };
51    for static_pda in static_pdas {
52        res.extend(static_pda_gen(&static_pda));
53    }
54    res.into()
55}
56
57/// Create a `Pubkey` with [`Pubkey::create_with_seed`](https://docs.rs/solana-program/latest/solana_program/pubkey/struct.Pubkey.html#method.create_with_seed).
58///
59/// Example:
60///
61/// ```rust
62/// // args: (base, seed, owner)
63/// sanctum_macros::create_with_seed!(
64///     "9BoN4yBYwH63LFM9fDamaHK62YjM56hWYZqok7MnAakJ",
65///     "seed",
66///     "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
67/// );
68/// ````
69#[proc_macro]
70pub fn create_with_seed(input: TokenStream) -> TokenStream {
71    let CreateWithSeedArgs {
72        pubkey,
73        base_lit_str,
74        base,
75        seed_lit_str,
76        owner_lit_str,
77        owner,
78    } = parse_macro_input!(input);
79
80    let id_consts = gen_pubkey_consts("", pubkey);
81    let base_consts = gen_pubkey_consts_with_litstr("BASE", base, base_lit_str);
82    let seed_const_ident = format_ident!("SEED");
83    let owner_consts = gen_pubkey_consts_with_litstr("OWNER", owner, owner_lit_str);
84
85    quote! {
86        #id_consts
87        #base_consts
88        pub const #seed_const_ident: &str = #seed_lit_str;
89        #owner_consts
90    }
91    .into()
92}