stellar_axelar_std_derive/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
//! Note: The tests are located in the `stellar-axelar-std` package instead of `stellar-axelar-std-derive`
//!
//! This ensures compatibility and prevents cyclic dependency issues during testing and release.
mod event;
mod its_executable;
mod operatable;
mod ownable;
mod upgradable;
use proc_macro::TokenStream;
#[cfg(any(test, feature = "testutils"))]
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
use upgradable::MigrationArgs;
/// Implements the Operatable interface for a Soroban contract.
///
/// # Example
/// ```rust,ignore
/// # mod test {
/// # use soroban_sdk::{contract, contractimpl, Address, Env};
/// use stellar_axelar_std_derive::Operatable;
///
/// #[contract]
/// #[derive(Operatable)]
/// pub struct Contract;
///
/// #[contractimpl]
/// impl Contract {
/// pub fn __constructor(env: &Env, owner: Address) {
/// stellar_axelar_std::interfaces::set_operator(env, &owner);
/// }
/// }
/// # }
/// ```
#[proc_macro_derive(Operatable)]
pub fn derive_operatable(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
operatable::operatable(name).into()
}
/// Implements the Ownable interface for a Soroban contract.
///
/// # Example
/// ```rust,ignore
/// # mod test {
/// # use soroban_sdk::{contract, contractimpl, Address, Env};
/// use stellar_axelar_std_derive::Ownable;
///
/// #[contract]
/// #[derive(Ownable)]
/// pub struct Contract;
///
/// #[contractimpl]
/// impl Contract {
/// pub fn __constructor(env: &Env, owner: Address) {
/// stellar_axelar_std::interfaces::set_owner(env, &owner);
/// }
/// }
/// # }
/// ```
#[proc_macro_derive(Ownable)]
pub fn derive_ownable(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
ownable::ownable(name).into()
}
/// Implements the Upgradable and Migratable interfaces for a Soroban contract.
///
/// A `ContractError` error type must be defined in scope, and have a `MigrationNotAllowed` variant.
///
/// # Example
/// ```rust,ignore
/// # mod test {
/// # use soroban_sdk::{contract, contractimpl, contracterror, Address, Env};
/// use stellar_axelar_std_derive::{Ownable, Upgradable};
/// # #[contracterror]
/// # #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
/// # #[repr(u32)]
/// # pub enum ContractError {
/// # MigrationNotAllowed = 1,
/// # }
///
/// #[contract]
/// #[derive(Ownable, Upgradable)]
/// #[migratable(with_type = Address)]
/// pub struct Contract;
///
/// #[contractimpl]
/// impl Contract {
/// pub fn __constructor(env: &Env, owner: Address) {
/// stellar_axelar_std::interfaces::set_owner(env, &owner);
/// }
/// }
///
/// impl Contract {
/// fn run_migration(env: &Env, new_owner: Address) {
/// Self::transfer_ownership(env, new_owner);
/// }
/// }
/// # }
/// ```
#[proc_macro_derive(Upgradable, attributes(migratable))]
pub fn derive_upgradable(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let args = input
.attrs
.iter()
.find(|attr| attr.path().is_ident("migratable"))
.map(|attr| attr.parse_args::<MigrationArgs>())
.transpose()
.unwrap_or_else(|e| panic!("{}", e))
.unwrap_or_else(MigrationArgs::default);
upgradable::upgradable(name, args).into()
}
/// Implements the Event and EventTestUtils traits for a Soroban contract event.
///
/// Fields without a `#[data]` attribute are used as topics, while fields with `#[data]` are used as event data.
/// The event name can be specified with `#[event_name(...)]` or will default to the struct name in snake_case (minus "Event" suffix).
///
/// # Example
/// ```rust,ignore
/// # mod test {
/// use core::fmt::Debug;
/// use stellar_axelar_std::events::Event;
/// use stellar_axelar_std::IntoEvent;
/// use soroban_sdk::{Address, contract, contractimpl, Env, String};
///
/// #[derive(Debug, PartialEq, IntoEvent)]
/// #[event_name("transfer")]
/// pub struct TransferEvent {
/// pub from: Address,
/// pub to: Address,
/// #[data]
/// pub amount: String,
/// }
///
/// #[contract]
/// pub struct Token;
///
/// #[contractimpl]
/// impl Token {
/// pub fn transfer(env: &Env, to: Address, amount: String) {
/// // ... transfer logic ...
///
/// // Generates event with:
/// // - Topics: ["transfer", contract_address, to]
/// // - Data: [amount]
/// TransferEvent {
/// from: env.current_contract_address(),
/// to,
/// amount,
/// }.emit(env);
/// }
/// }
/// }
/// ```
#[proc_macro_derive(IntoEvent, attributes(data, event_name))]
pub fn derive_into_event(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let event_impl = event::derive_event_impl(&input);
#[cfg(any(test, feature = "testutils"))]
let event_impl = {
let event_test_impl = event::derive_event_testutils_impl(&input);
quote! {
#event_impl
#event_test_impl
}
};
event_impl.into()
}
#[proc_macro_derive(InterchainTokenExecutable)]
pub fn derive_its_executable(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
its_executable::its_executable(name).into()
}