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}