mainstay_lang/
lib.rs

1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
2
3//! Mainstay ⚓ is a framework for Solana's Sealevel runtime providing several
4//! convenient developer tools.
5//!
6//! - Rust eDSL for writing safe, secure, and high level Solana programs
7//! - [IDL](https://en.wikipedia.org/wiki/Interface_description_language) specification
8//! - TypeScript package for generating clients from IDL
9//! - CLI and workspace management for developing complete applications
10//!
11//! If you're familiar with developing in Ethereum's
12//! [Solidity](https://docs.soliditylang.org/en/v0.7.4/),
13//! [Truffle](https://www.trufflesuite.com/),
14//! [web3.js](https://github.com/ethereum/web3.js) or Parity's
15//! [Ink!](https://github.com/paritytech/ink), then the experience will be
16//! familiar. Although the syntax and semantics are targeted at Solana, the high
17//! level workflow of writing RPC request handlers, emitting an IDL, and
18//! generating clients from IDL is the same.
19//!
20//! For detailed tutorials and examples on how to use Mainstay, see the guided
21//! [tutorials](https://mainstay-lang.com) or examples in the GitHub
22//! [repository](https://github.com/nxpkg/mainstay).
23//!
24//! Presented here are the Rust primitives for building on Solana.
25
26extern crate self as mainstay_lang;
27
28use bytemuck::{Pod, Zeroable};
29use solana_program::account_info::AccountInfo;
30use solana_program::instruction::AccountMeta;
31use solana_program::program_error::ProgramError;
32use solana_program::pubkey::Pubkey;
33use std::{collections::BTreeSet, fmt::Debug, io::Write};
34
35mod account_meta;
36pub mod accounts;
37mod bpf_upgradeable_state;
38mod bpf_writer;
39mod common;
40pub mod context;
41pub mod error;
42#[doc(hidden)]
43pub mod event;
44#[doc(hidden)]
45pub mod idl;
46pub mod system_program;
47mod vec;
48
49#[cfg(feature = "lazy-account")]
50mod lazy;
51
52pub use crate::bpf_upgradeable_state::*;
53pub use mainstay_attribute_access_control::access_control;
54pub use mainstay_attribute_account::{account, declare_id, pubkey, zero_copy};
55pub use mainstay_attribute_constant::constant;
56pub use mainstay_attribute_error::*;
57pub use mainstay_attribute_event::{emit, event};
58pub use mainstay_attribute_program::{declare_program, instruction, program};
59pub use mainstay_derive_accounts::Accounts;
60pub use mainstay_derive_serde::{MainstayDeserialize, MainstaySerialize};
61pub use mainstay_derive_space::InitSpace;
62
63/// Borsh is the default serialization format for instructions and accounts.
64pub use borsh::de::BorshDeserialize as MainstayDeserialize;
65pub use borsh::ser::BorshSerialize as MainstaySerialize;
66pub use solana_program;
67
68#[cfg(feature = "event-cpi")]
69pub use mainstay_attribute_event::{emit_cpi, event_cpi};
70
71#[cfg(feature = "idl-build")]
72pub use idl::IdlBuild;
73
74#[cfg(feature = "interface-instructions")]
75pub use mainstay_attribute_program::interface;
76
77pub type Result<T> = std::result::Result<T, error::Error>;
78
79/// A data structure of validated accounts that can be deserialized from the
80/// input to a Solana program. Implementations of this trait should perform any
81/// and all requisite constraint checks on accounts to ensure the accounts
82/// maintain any invariants required for the program to run securely. In most
83/// cases, it's recommended to use the [`Accounts`](./derive.Accounts.html)
84/// derive macro to implement this trait.
85///
86/// Generics:
87/// -   `B`: the type of the PDA bumps cache struct generated by the `Accounts` struct.
88///     For example,
89/// ```rust,ignore
90/// pub struct Example<'info> {
91///     #[account(
92///         init,
93///         seeds = [...],
94///         bump,
95///     )]
96///     pub pda_1: UncheckedAccount<'info>,
97///     pub not_pda: UncheckedAccount<'info>,
98/// }
99/// ```
100///
101///    generates:
102///
103/// ```rust,ignore
104/// pub struct ExampleBumps {
105///     pub pda_1: u8,
106/// }
107/// ```
108pub trait Accounts<'info, B>: ToAccountMetas + ToAccountInfos<'info> + Sized {
109    /// Returns the validated accounts struct. What constitutes "valid" is
110    /// program dependent. However, users of these types should never have to
111    /// worry about account substitution attacks. For example, if a program
112    /// expects a `Mint` account from the SPL token program  in a particular
113    /// field, then it should be impossible for this method to return `Ok` if
114    /// any other account type is given--from the SPL token program or elsewhere.
115    ///
116    /// `program_id` is the currently executing program. `accounts` is the
117    /// set of accounts to construct the type from. For every account used,
118    /// the implementation should mutate the slice, consuming the used entry
119    /// so that it cannot be used again.
120    fn try_accounts(
121        program_id: &Pubkey,
122        accounts: &mut &'info [AccountInfo<'info>],
123        ix_data: &[u8],
124        bumps: &mut B,
125        reallocs: &mut BTreeSet<Pubkey>,
126    ) -> Result<Self>;
127}
128
129/// Associated bump seeds for `Accounts`.
130pub trait Bumps {
131    /// Struct to hold account bump seeds.
132    type Bumps: Sized + Debug;
133}
134
135/// The exit procedure for an account. Any cleanup or persistence to storage
136/// should be done here.
137pub trait AccountsExit<'info>: ToAccountMetas + ToAccountInfos<'info> {
138    /// `program_id` is the currently executing program.
139    fn exit(&self, _program_id: &Pubkey) -> Result<()> {
140        // no-op
141        Ok(())
142    }
143}
144
145/// The close procedure to initiate garabage collection of an account, allowing
146/// one to retrieve the rent exemption.
147pub trait AccountsClose<'info>: ToAccountInfos<'info> {
148    fn close(&self, sol_destination: AccountInfo<'info>) -> Result<()>;
149}
150
151/// Transformation to
152/// [`AccountMeta`](../solana_program/instruction/struct.AccountMeta.html)
153/// structs.
154pub trait ToAccountMetas {
155    /// `is_signer` is given as an optional override for the signer meta field.
156    /// This covers the edge case when a program-derived-address needs to relay
157    /// a transaction from a client to another program but sign the transaction
158    /// before the relay. The client cannot mark the field as a signer, and so
159    /// we have to override the is_signer meta field given by the client.
160    fn to_account_metas(&self, is_signer: Option<bool>) -> Vec<AccountMeta>;
161}
162
163/// Transformation to
164/// [`AccountInfo`](../solana_program/account_info/struct.AccountInfo.html)
165/// structs.
166pub trait ToAccountInfos<'info> {
167    fn to_account_infos(&self) -> Vec<AccountInfo<'info>>;
168}
169
170/// Transformation to an `AccountInfo` struct.
171pub trait ToAccountInfo<'info> {
172    fn to_account_info(&self) -> AccountInfo<'info>;
173}
174
175impl<'info, T> ToAccountInfo<'info> for T
176where
177    T: AsRef<AccountInfo<'info>>,
178{
179    fn to_account_info(&self) -> AccountInfo<'info> {
180        self.as_ref().clone()
181    }
182}
183
184/// Lamports related utility methods for accounts.
185pub trait Lamports<'info>: AsRef<AccountInfo<'info>> {
186    /// Get the lamports of the account.
187    fn get_lamports(&self) -> u64 {
188        self.as_ref().lamports()
189    }
190
191    /// Add lamports to the account.
192    ///
193    /// This method is useful for transferring lamports from a PDA.
194    ///
195    /// # Requirements
196    ///
197    /// 1. The account must be marked `mut`.
198    /// 2. The total lamports **before** the transaction must equal to total lamports **after**
199    ///    the transaction.
200    /// 3. `lamports` field of the account info should not currently be borrowed.
201    ///
202    /// See [`Lamports::sub_lamports`] for subtracting lamports.
203    fn add_lamports(&self, amount: u64) -> Result<&Self> {
204        **self.as_ref().try_borrow_mut_lamports()? = self
205            .get_lamports()
206            .checked_add(amount)
207            .ok_or(ProgramError::ArithmeticOverflow)?;
208        Ok(self)
209    }
210
211    /// Subtract lamports from the account.
212    ///
213    /// This method is useful for transferring lamports from a PDA.
214    ///
215    /// # Requirements
216    ///
217    /// 1. The account must be owned by the executing program.
218    /// 2. The account must be marked `mut`.
219    /// 3. The total lamports **before** the transaction must equal to total lamports **after**
220    ///    the transaction.
221    /// 4. `lamports` field of the account info should not currently be borrowed.
222    ///
223    /// See [`Lamports::add_lamports`] for adding lamports.
224    fn sub_lamports(&self, amount: u64) -> Result<&Self> {
225        **self.as_ref().try_borrow_mut_lamports()? = self
226            .get_lamports()
227            .checked_sub(amount)
228            .ok_or(ProgramError::ArithmeticOverflow)?;
229        Ok(self)
230    }
231}
232
233impl<'info, T: AsRef<AccountInfo<'info>>> Lamports<'info> for T {}
234
235/// A data structure that can be serialized and stored into account storage,
236/// i.e. an
237/// [`AccountInfo`](../solana_program/account_info/struct.AccountInfo.html#structfield.data)'s
238/// mutable data slice.
239///
240/// Implementors of this trait should ensure that any subsequent usage of the
241/// `AccountDeserialize` trait succeeds if and only if the account is of the
242/// correct type.
243///
244/// In most cases, one can use the default implementation provided by the
245/// [`#[account]`](./attr.account.html) attribute.
246pub trait AccountSerialize {
247    /// Serializes the account data into `writer`.
248    fn try_serialize<W: Write>(&self, _writer: &mut W) -> Result<()> {
249        Ok(())
250    }
251}
252
253/// A data structure that can be deserialized and stored into account storage,
254/// i.e. an
255/// [`AccountInfo`](../solana_program/account_info/struct.AccountInfo.html#structfield.data)'s
256/// mutable data slice.
257pub trait AccountDeserialize: Sized {
258    /// Deserializes previously initialized account data. Should fail for all
259    /// uninitialized accounts, where the bytes are zeroed. Implementations
260    /// should be unique to a particular account type so that one can never
261    /// successfully deserialize the data of one account type into another.
262    /// For example, if the SPL token program were to implement this trait,
263    /// it should be impossible to deserialize a `Mint` account into a token
264    /// `Account`.
265    fn try_deserialize(buf: &mut &[u8]) -> Result<Self> {
266        Self::try_deserialize_unchecked(buf)
267    }
268
269    /// Deserializes account data without checking the account discriminator.
270    /// This should only be used on account initialization, when the bytes of
271    /// the account are zeroed.
272    fn try_deserialize_unchecked(buf: &mut &[u8]) -> Result<Self>;
273}
274
275/// An account data structure capable of zero copy deserialization.
276pub trait ZeroCopy: Discriminator + Copy + Clone + Zeroable + Pod {}
277
278/// Calculates the data for an instruction invocation, where the data is
279/// `Discriminator + BorshSerialize(args)`. `args` is a borsh serialized
280/// struct of named fields for each argument given to an instruction.
281pub trait InstructionData: Discriminator + MainstaySerialize {
282    fn data(&self) -> Vec<u8> {
283        let mut data = Vec::with_capacity(256);
284        data.extend_from_slice(Self::DISCRIMINATOR);
285        self.serialize(&mut data).unwrap();
286        data
287    }
288
289    /// Clears `data` and writes instruction data to it.
290    ///
291    /// We use a `Vec<u8>`` here because of the additional flexibility of re-allocation (only if
292    /// necessary), and because the data field in `Instruction` expects a `Vec<u8>`.
293    fn write_to(&self, mut data: &mut Vec<u8>) {
294        data.clear();
295        data.extend_from_slice(Self::DISCRIMINATOR);
296        self.serialize(&mut data).unwrap()
297    }
298}
299
300/// An event that can be emitted via a Solana log. See [`emit!`](crate::prelude::emit) for an example.
301pub trait Event: MainstaySerialize + MainstayDeserialize + Discriminator {
302    fn data(&self) -> Vec<u8>;
303}
304
305/// Unique identifier for a type.
306///
307/// This is not a trait you should derive manually, as various Mainstay macros already derive it
308/// internally.
309///
310/// Prior to Mainstay v0.31, discriminators were always 8 bytes in size. However, starting with Mainstay
311/// v0.31, it is possible to override the default discriminators, and discriminator length is no
312/// longer fixed, which means this trait can also be implemented for non-Mainstay programs.
313///
314/// It's important that the discriminator is always unique for the type you're implementing it
315/// for. While the discriminator can be at any length (including zero), the IDL generation does not
316/// currently allow empty discriminators for safety and convenience reasons. However, the trait
317/// definition still allows empty discriminators because some non-Mainstay programs, e.g. the SPL
318/// Token program, don't have account discriminators. In that case, safety checks should never
319/// depend on the discriminator.
320pub trait Discriminator {
321    /// Discriminator slice.
322    ///
323    /// See [`Discriminator`] trait documentation for more information.
324    const DISCRIMINATOR: &'static [u8];
325}
326
327/// Defines the space of an account for initialization.
328pub trait Space {
329    const INIT_SPACE: usize;
330}
331
332/// Bump seed for program derived addresses.
333pub trait Bump {
334    fn seed(&self) -> u8;
335}
336
337/// Defines an address expected to own an account.
338pub trait Owner {
339    fn owner() -> Pubkey;
340}
341
342/// Defines a list of addresses expected to own an account.
343pub trait Owners {
344    fn owners() -> &'static [Pubkey];
345}
346
347/// Defines a trait for checking the owner of a program.
348pub trait CheckOwner {
349    fn check_owner(owner: &Pubkey) -> Result<()>;
350}
351
352impl<T: Owners> CheckOwner for T {
353    fn check_owner(owner: &Pubkey) -> Result<()> {
354        if !Self::owners().contains(owner) {
355            Err(
356                error::Error::from(error::ErrorCode::AccountOwnedByWrongProgram)
357                    .with_account_name(*owner),
358            )
359        } else {
360            Ok(())
361        }
362    }
363}
364
365/// Defines the id of a program.
366pub trait Id {
367    fn id() -> Pubkey;
368}
369
370/// Defines the possible ids of a program.
371pub trait Ids {
372    fn ids() -> &'static [Pubkey];
373}
374
375/// Defines a trait for checking the id of a program.
376pub trait CheckId {
377    fn check_id(id: &Pubkey) -> Result<()>;
378}
379
380impl<T: Ids> CheckId for T {
381    fn check_id(id: &Pubkey) -> Result<()> {
382        if !Self::ids().contains(id) {
383            Err(error::Error::from(error::ErrorCode::InvalidProgramId).with_account_name(*id))
384        } else {
385            Ok(())
386        }
387    }
388}
389
390/// Defines the Pubkey of an account.
391pub trait Key {
392    fn key(&self) -> Pubkey;
393}
394
395impl Key for Pubkey {
396    fn key(&self) -> Pubkey {
397        *self
398    }
399}
400
401/// The prelude contains all commonly used components of the crate.
402/// All programs should include it via `mainstay_lang::prelude::*;`.
403pub mod prelude {
404    pub use super::{
405        access_control, account, accounts::account::Account,
406        accounts::account_loader::AccountLoader, accounts::interface::Interface,
407        accounts::interface_account::InterfaceAccount, accounts::program::Program,
408        accounts::signer::Signer, accounts::system_account::SystemAccount,
409        accounts::sysvar::Sysvar, accounts::unchecked_account::UncheckedAccount, constant,
410        context::Context, context::CpiContext, declare_id, declare_program, emit, err, error,
411        event, instruction, program, pubkey, require, require_eq, require_gt, require_gte,
412        require_keys_eq, require_keys_neq, require_neq,
413        solana_program::bpf_loader_upgradeable::UpgradeableLoaderState, source,
414        system_program::System, zero_copy, AccountDeserialize, AccountSerialize, Accounts,
415        AccountsClose, AccountsExit, MainstayDeserialize, MainstaySerialize, Discriminator, Id,
416        InitSpace, Key, Lamports, Owner, ProgramData, Result, Space, ToAccountInfo, ToAccountInfos,
417        ToAccountMetas,
418    };
419    pub use mainstay_attribute_error::*;
420    pub use borsh;
421    pub use error::*;
422    pub use solana_program::account_info::{next_account_info, AccountInfo};
423    pub use solana_program::instruction::AccountMeta;
424    pub use solana_program::msg;
425    pub use solana_program::program_error::ProgramError;
426    pub use solana_program::pubkey::Pubkey;
427    pub use solana_program::sysvar::clock::Clock;
428    pub use solana_program::sysvar::epoch_schedule::EpochSchedule;
429    pub use solana_program::sysvar::instructions::Instructions;
430    pub use solana_program::sysvar::rent::Rent;
431    pub use solana_program::sysvar::rewards::Rewards;
432    pub use solana_program::sysvar::slot_hashes::SlotHashes;
433    pub use solana_program::sysvar::slot_history::SlotHistory;
434    pub use solana_program::sysvar::stake_history::StakeHistory;
435    pub use solana_program::sysvar::Sysvar as SolanaSysvar;
436    pub use thiserror;
437
438    #[cfg(feature = "event-cpi")]
439    pub use super::{emit_cpi, event_cpi};
440
441    #[cfg(feature = "idl-build")]
442    pub use super::idl::IdlBuild;
443
444    #[cfg(feature = "interface-instructions")]
445    pub use super::interface;
446
447    #[cfg(feature = "lazy-account")]
448    pub use super::accounts::lazy_account::LazyAccount;
449}
450
451/// Internal module used by macros and unstable apis.
452#[doc(hidden)]
453pub mod __private {
454    pub use mainstay_attribute_account::ZeroCopyAccessor;
455    pub use base64;
456    pub use bytemuck;
457
458    pub use crate::{bpf_writer::BpfWriter, common::is_closed};
459
460    use solana_program::pubkey::Pubkey;
461
462    // Used to calculate the maximum between two expressions.
463    // It is necessary for the calculation of the enum space.
464    #[doc(hidden)]
465    pub const fn max(a: usize, b: usize) -> usize {
466        [a, b][(a < b) as usize]
467    }
468
469    // Very experimental trait.
470    #[doc(hidden)]
471    pub trait ZeroCopyAccessor<Ty> {
472        fn get(&self) -> Ty;
473        fn set(input: &Ty) -> Self;
474    }
475
476    #[doc(hidden)]
477    impl ZeroCopyAccessor<Pubkey> for [u8; 32] {
478        fn get(&self) -> Pubkey {
479            Pubkey::from(*self)
480        }
481        fn set(input: &Pubkey) -> [u8; 32] {
482            input.to_bytes()
483        }
484    }
485
486    #[cfg(feature = "lazy-account")]
487    pub use crate::lazy::Lazy;
488    #[cfg(feature = "lazy-account")]
489    pub use mainstay_derive_serde::Lazy;
490}
491
492/// Ensures a condition is true, otherwise returns with the given error.
493/// Use this with or without a custom error type.
494///
495/// # Example
496/// ```ignore
497/// // Instruction function
498/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
499///     require!(ctx.accounts.data.mutation_allowed, MyError::MutationForbidden);
500///     ctx.accounts.data.data = data;
501///     Ok(())
502/// }
503///
504/// // An enum for custom error codes
505/// #[error_code]
506/// pub enum MyError {
507///     MutationForbidden
508/// }
509///
510/// // An account definition
511/// #[account]
512/// #[derive(Default)]
513/// pub struct MyData {
514///     mutation_allowed: bool,
515///     data: u64
516/// }
517///
518/// // An account validation struct
519/// #[derive(Accounts)]
520/// pub struct SetData<'info> {
521///     #[account(mut)]
522///     pub data: Account<'info, MyData>
523/// }
524/// ```
525#[macro_export]
526macro_rules! require {
527    ($invariant:expr, $error:tt $(,)?) => {
528        if !($invariant) {
529            return Err(mainstay_lang::error!($crate::ErrorCode::$error));
530        }
531    };
532    ($invariant:expr, $error:expr $(,)?) => {
533        if !($invariant) {
534            return Err(mainstay_lang::error!($error));
535        }
536    };
537}
538
539/// Ensures two NON-PUBKEY values are equal.
540///
541/// Use [require_keys_eq](crate::prelude::require_keys_eq)
542/// to compare two pubkeys.
543///
544/// Can be used with or without a custom error code.
545///
546/// # Example
547/// ```rust,ignore
548/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
549///     require_eq!(ctx.accounts.data.data, 0);
550///     ctx.accounts.data.data = data;
551///     Ok(())
552/// }
553/// ```
554#[macro_export]
555macro_rules! require_eq {
556    ($value1: expr, $value2: expr, $error_code:expr $(,)?) => {
557        if $value1 != $value2 {
558            return Err(error!($error_code).with_values(($value1, $value2)));
559        }
560    };
561    ($value1: expr, $value2: expr $(,)?) => {
562        if $value1 != $value2 {
563            return Err(error!(mainstay_lang::error::ErrorCode::RequireEqViolated)
564                .with_values(($value1, $value2)));
565        }
566    };
567}
568
569/// Ensures two NON-PUBKEY values are not equal.
570///
571/// Use [require_keys_neq](crate::prelude::require_keys_neq)
572/// to compare two pubkeys.
573///
574/// Can be used with or without a custom error code.
575///
576/// # Example
577/// ```rust,ignore
578/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
579///     require_neq!(ctx.accounts.data.data, 0);
580///     ctx.accounts.data.data = data;
581///     Ok(());
582/// }
583/// ```
584#[macro_export]
585macro_rules! require_neq {
586    ($value1: expr, $value2: expr, $error_code: expr $(,)?) => {
587        if $value1 == $value2 {
588            return Err(error!($error_code).with_values(($value1, $value2)));
589        }
590    };
591    ($value1: expr, $value2: expr $(,)?) => {
592        if $value1 == $value2 {
593            return Err(error!(mainstay_lang::error::ErrorCode::RequireNeqViolated)
594                .with_values(($value1, $value2)));
595        }
596    };
597}
598
599/// Ensures two pubkeys values are equal.
600///
601/// Use [require_eq](crate::prelude::require_eq)
602/// to compare two non-pubkey values.
603///
604/// Can be used with or without a custom error code.
605///
606/// # Example
607/// ```rust,ignore
608/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
609///     require_keys_eq!(ctx.accounts.data.authority.key(), ctx.accounts.authority.key());
610///     ctx.accounts.data.data = data;
611///     Ok(())
612/// }
613/// ```
614#[macro_export]
615macro_rules! require_keys_eq {
616    ($value1: expr, $value2: expr, $error_code:expr $(,)?) => {
617        if $value1 != $value2 {
618            return Err(error!($error_code).with_pubkeys(($value1, $value2)));
619        }
620    };
621    ($value1: expr, $value2: expr $(,)?) => {
622        if $value1 != $value2 {
623            return Err(error!(mainstay_lang::error::ErrorCode::RequireKeysEqViolated)
624                .with_pubkeys(($value1, $value2)));
625        }
626    };
627}
628
629/// Ensures two pubkeys are not equal.
630///
631/// Use [require_neq](crate::prelude::require_neq)
632/// to compare two non-pubkey values.
633///
634/// Can be used with or without a custom error code.
635///
636/// # Example
637/// ```rust,ignore
638/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
639///     require_keys_neq!(ctx.accounts.data.authority.key(), ctx.accounts.other.key());
640///     ctx.accounts.data.data = data;
641///     Ok(())
642/// }
643/// ```
644#[macro_export]
645macro_rules! require_keys_neq {
646    ($value1: expr, $value2: expr, $error_code: expr $(,)?) => {
647        if $value1 == $value2 {
648            return Err(error!($error_code).with_pubkeys(($value1, $value2)));
649        }
650    };
651    ($value1: expr, $value2: expr $(,)?) => {
652        if $value1 == $value2 {
653            return Err(
654                error!(mainstay_lang::error::ErrorCode::RequireKeysNeqViolated)
655                    .with_pubkeys(($value1, $value2)),
656            );
657        }
658    };
659}
660
661/// Ensures the first NON-PUBKEY value is greater than the second
662/// NON-PUBKEY value.
663///
664/// To include an equality check, use [require_gte](crate::require_gte).
665///
666/// Can be used with or without a custom error code.
667///
668/// # Example
669/// ```rust,ignore
670/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
671///     require_gt!(ctx.accounts.data.data, 0);
672///     ctx.accounts.data.data = data;
673///     Ok(());
674/// }
675/// ```
676#[macro_export]
677macro_rules! require_gt {
678    ($value1: expr, $value2: expr, $error_code: expr $(,)?) => {
679        if $value1 <= $value2 {
680            return Err(error!($error_code).with_values(($value1, $value2)));
681        }
682    };
683    ($value1: expr, $value2: expr $(,)?) => {
684        if $value1 <= $value2 {
685            return Err(error!(mainstay_lang::error::ErrorCode::RequireGtViolated)
686                .with_values(($value1, $value2)));
687        }
688    };
689}
690
691/// Ensures the first NON-PUBKEY value is greater than or equal
692/// to the second NON-PUBKEY value.
693///
694/// Can be used with or without a custom error code.
695///
696/// # Example
697/// ```rust,ignore
698/// pub fn set_data(ctx: Context<SetData>, data: u64) -> Result<()> {
699///     require_gte!(ctx.accounts.data.data, 1);
700///     ctx.accounts.data.data = data;
701///     Ok(());
702/// }
703/// ```
704#[macro_export]
705macro_rules! require_gte {
706    ($value1: expr, $value2: expr, $error_code: expr $(,)?) => {
707        if $value1 < $value2 {
708            return Err(error!($error_code).with_values(($value1, $value2)));
709        }
710    };
711    ($value1: expr, $value2: expr $(,)?) => {
712        if $value1 < $value2 {
713            return Err(error!(mainstay_lang::error::ErrorCode::RequireGteViolated)
714                .with_values(($value1, $value2)));
715        }
716    };
717}
718
719/// Returns with the given error.
720/// Use this with a custom error type.
721///
722/// # Example
723/// ```ignore
724/// // Instruction function
725/// pub fn example(ctx: Context<Example>) -> Result<()> {
726///     err!(MyError::SomeError)
727/// }
728///
729/// // An enum for custom error codes
730/// #[error_code]
731/// pub enum MyError {
732///     SomeError
733/// }
734/// ```
735#[macro_export]
736macro_rules! err {
737    ($error:tt $(,)?) => {
738        Err(mainstay_lang::error!($crate::ErrorCode::$error))
739    };
740    ($error:expr $(,)?) => {
741        Err(mainstay_lang::error!($error))
742    };
743}
744
745/// Creates a [`Source`](crate::error::Source)
746#[macro_export]
747macro_rules! source {
748    () => {
749        mainstay_lang::error::Source {
750            filename: file!(),
751            line: line!(),
752        }
753    };
754}