Skip to main content

rialo_sol_attribute_program/
lib.rs

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