rialo_sol_attribute_program/lib.rs
1// Copyright (c) Subzero Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4extern crate proc_macro;
5
6mod declare_program;
7
8use declare_program::DeclareProgram;
9use quote::ToTokens;
10use syn::parse_macro_input;
11
12/// The `#[program]` attribute defines the module containing all instruction
13/// handlers defining all entries into a Solana program.
14#[proc_macro_attribute]
15pub fn program(
16 _args: proc_macro::TokenStream,
17 input: proc_macro::TokenStream,
18) -> proc_macro::TokenStream {
19 parse_macro_input!(input as rialo_sol_syn::Program)
20 .to_token_stream()
21 .into()
22}
23
24/// Declare an external program based on its IDL.
25///
26/// The IDL of the program must exist in a directory named `idls`. This directory can be at any
27/// depth, e.g. both inside the program's directory (`<PROGRAM_DIR>/idls`) and inside Anchor
28/// workspace root directory (`<PROGRAM_DIR>/../../idls`) are valid.
29///
30/// # Usage
31///
32/// ```rs
33/// declare_program!(program_name);
34/// ```
35///
36/// This generates a module named `program_name` that can be used to interact with the program
37/// without having to add the program's crate as a dependency.
38///
39/// Both on-chain and off-chain usage is supported.
40///
41/// Use `cargo doc --open` to see the generated modules and their documentation.
42///
43/// # Note
44///
45/// Re-defining the same program to use the same definitions should be avoided since this results
46/// in a larger binary size.
47///
48/// A program should only be defined once. If you have multiple programs that depend on the same
49/// definition, you should consider creating a separate crate for the external program definition
50/// and reusing it in your programs.
51///
52/// # Example
53///
54/// A full on-chain CPI usage example can be found [here].
55///
56/// [here]: https://github.com/coral-xyz/anchor/tree/v0.32.0/tests/declare-program
57#[proc_macro]
58pub fn declare_program(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
59 parse_macro_input!(input as DeclareProgram)
60 .to_token_stream()
61 .into()
62}
63
64/// The `#[interface]` attribute is used to mark an instruction as belonging
65/// to an interface implementation, thus transforming its discriminator to the
66/// proper bytes for that interface instruction.
67///
68/// # Example
69///
70/// ```rust,ignore
71/// use rialo_sol_lang::prelude::*;
72///
73/// // SPL Transfer Hook Interface: `Execute` instruction.
74/// //
75/// // This instruction is invoked by Token-2022 when a transfer occurs,
76/// // if a mint has specified this program as its transfer hook.
77/// #[interface(spl_transfer_hook_interface::execute)]
78/// pub fn execute_transfer(ctx: Context<Execute>, amount: u64) -> Result<()> {
79/// // Check that all extra accounts were provided
80/// let data = ctx.accounts.extra_metas_account.try_borrow_data()?;
81/// ExtraAccountMetaList::check_account_infos::<ExecuteInstruction>(
82/// &ctx.accounts.to_account_infos(),
83/// &TransferHookInstruction::Execute { amount }.pack(),
84/// &ctx.program_id,
85/// &data,
86/// )?;
87///
88/// // Or maybe perform some custom logic
89/// if ctx.accounts.token_metadata.mint != ctx.accounts.token_account.mint {
90/// return Err(ProgramError::IncorrectAccount);
91/// }
92///
93/// Ok(())
94/// }
95/// ```
96#[cfg(feature = "interface-instructions")]
97#[deprecated(
98 since = "0.32.0",
99 note = "Use `#[instruction(discriminator = <EXPR>)]` instead.
100 See examples in https://github.com/coral-xyz/anchor/tree/v0.32.0/tests/spl/transfer-hook"
101)]
102#[proc_macro_attribute]
103pub fn interface(
104 _args: proc_macro::TokenStream,
105 input: proc_macro::TokenStream,
106) -> proc_macro::TokenStream {
107 // This macro itself is a no-op, but must be defined as a proc-macro
108 // attribute to be used on a function as the `#[interface]` attribute.
109 //
110 // The `#[program]` macro will detect this attribute and transform the
111 // discriminator.
112 input
113}
114
115/// This attribute is used to override the Anchor defaults of program instructions.
116///
117/// # Arguments
118///
119/// - `discriminator`: Override the default 8-byte discriminator
120///
121/// **Usage:** `discriminator = <CONST_EXPR>`
122///
123/// All constant expressions are supported.
124///
125/// **Examples:**
126///
127/// - `discriminator = 1` (shortcut for `[1]`)
128/// - `discriminator = [1, 2, 3, 4]`
129/// - `discriminator = b"hi"`
130/// - `discriminator = MY_DISC`
131/// - `discriminator = get_disc(...)`
132///
133/// # Example
134///
135/// ```ignore
136/// use rialo_sol_lang::prelude::*;
137///
138/// declare_id!("CustomDiscriminator111111111111111111111111");
139///
140/// #[program]
141/// pub mod custom_discriminator {
142/// use super::*;
143///
144/// #[instruction(discriminator = [1, 2, 3, 4])]
145/// pub fn my_ix(_ctx: Context<MyIx>) -> Result<()> {
146/// Ok(())
147/// }
148/// }
149///
150/// #[derive(Accounts)]
151/// pub struct MyIx<'info> {
152/// pub signer: Signer<'info>,
153/// }
154/// ```
155#[proc_macro_attribute]
156pub fn instruction(
157 _args: proc_macro::TokenStream,
158 input: proc_macro::TokenStream,
159) -> proc_macro::TokenStream {
160 // This macro itself is a no-op, but the `#[program]` macro will detect this attribute and use
161 // the arguments to transform the instruction.
162 input
163}