tensor_vipers/
assert.rs

1//! Various assertions.
2#![allow(clippy::all)]
3
4/// Runs a block, returning a [anchor_lang::prelude::Result<()>].
5#[macro_export]
6macro_rules! test_assertion {
7    ($body: block) => {
8        (|| -> crate::Result<()> {
9            $body
10            Ok(())
11        })()
12    };
13}
14
15/// Asserts that the given assertion block does not throw any errors.
16///
17/// Recommended for use in tests only.
18#[macro_export]
19macro_rules! assert_does_not_throw {
20    ($body: block $(,)?) => {
21        assert!($crate::test_assertion!($body).is_ok())
22    };
23}
24
25/// Asserts that the given assertion block throws a specific error.
26///
27/// Recommended for use in tests only.
28#[macro_export]
29macro_rules! assert_throws {
30    ($body: block, $right: expr $(,)?) => {
31        assert_eq!(
32            $crate::IntoCmpError::into_cmp_error($crate::test_assertion!($body).err()),
33            $crate::IntoCmpError::into_cmp_error(Some(::anchor_lang::prelude::error!($right)))
34        )
35    };
36}
37
38/// Formats an error as a `&str`.
39///
40/// # Example
41///
42/// ```
43/// # use anchor_lang::prelude::*;
44/// #[error_code]
45/// pub enum ErrorCode {
46///   #[msg("This is my error")]
47///   MyError
48/// }
49/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
50/// assert_eq!(format_err!(ErrorCode::MyError), "MyError: This is my error");
51/// # Ok(())
52/// # }
53/// ```
54#[macro_export]
55macro_rules! format_err {
56    ($err: expr) => {
57        &*format!("{:?}: {}", $err, $err)
58    };
59}
60
61/// Returns the given error as a program error.
62///
63/// # Example
64///
65/// ```
66/// # use anchor_lang::prelude::*;
67/// # #[error_code]
68/// # pub enum ErrorCode { MyError }
69/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
70/// let fail = false;
71/// if fail {
72///     return program_err!(MyError);
73/// }
74/// # Ok(())
75/// # }
76/// ```
77#[macro_export]
78macro_rules! program_err {
79    ($error:ident $(,)?) => {
80        Err(crate::ErrorCode::$error.into())
81    };
82}
83
84/// Logs where in the code the macro was invoked.
85#[macro_export]
86macro_rules! log_code_location {
87    () => {
88        msg!("Error thrown at {}:{}", file!(), line!());
89    };
90}
91
92/// Unwraps a block which returns an [Option].
93///
94/// This is useful for running checked math expressions within a function which returns [Result].
95///
96/// # Examples
97///
98/// ```
99/// # use anchor_lang::prelude::*;
100/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
101/// let result = unwrap_opt_block!({
102///     let one: u64 = 1;
103///     let three: u64 = 3;
104///     let four = one.checked_add(three)?;
105///     four.checked_add(3)
106/// });
107/// assert_eq!(result, 7);
108/// # Ok(())
109/// # }
110/// ```
111#[macro_export]
112macro_rules! unwrap_opt_block {
113    ($body:block $($arg:tt)*) => {
114        $crate::unwrap_opt!(
115            #[allow(clippy::redundant_closure_call)]
116            (|| { $body } )() $($arg)*)
117    };
118}
119
120/// Unwraps the result of a block of checked integer math.
121///
122/// # Example
123///
124/// ```
125/// # use anchor_lang::prelude::*;
126/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
127/// let result = unwrap_checked!({
128///   let one: u64 = 1;
129///   let three: u64 = 3;
130///   one.checked_add(three)
131/// });
132/// assert_eq!(result, 4);
133/// # Ok(())
134/// # }
135/// ```
136#[macro_export]
137macro_rules! unwrap_checked {
138    ($body:block $(,)?) => {
139        $crate::unwrap_opt_block!($body, $crate::VipersError::IntegerOverflow)
140    };
141}
142
143/// Throws an error.
144///
145/// # Example
146///
147/// ```
148/// # use anchor_lang::prelude::*;
149/// # #[error_code]
150/// # pub enum ErrorCode { MyError }
151/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
152/// let fail = false;
153/// if fail {
154///     throw_err!(MyError);
155/// }
156/// Ok(())
157/// # }
158/// ```
159#[macro_export]
160macro_rules! throw_err {
161    ($error:ident $(,)?) => {
162        $crate::throw_err!(crate::ErrorCode::$error);
163    };
164    ($error:expr $(,)?) => {
165        $crate::log_code_location!();
166        return Err(::anchor_lang::prelude::error!($error));
167    };
168}
169
170/// Asserts that the ATA is the one of the given owner/mint.
171///
172/// Warning: this uses a lot of compute units due to the need to generate a PDA.
173/// It is recommended to cache this value.
174#[cfg(feature = "spl-associated-token-account")]
175#[macro_export]
176#[deprecated(
177    since = "1.5.6",
178    note = "This uses a lot of compute units due to the need to generate a PDA. This is also not a valid way to check ownership since ATAs can be transferred. Use assert_keys_eq on the token account owner instead."
179)]
180macro_rules! assert_ata {
181    ($ata: expr, $owner: expr, $mint: expr $(,)?) => {
182        $crate::assert_ata!($ata, $owner, $mint, "ata mismatch")
183    };
184    ($ata: expr, $owner: expr, $mint: expr, $msg: expr $(,)?) => {{
185        let __ata = $crate::AsKeyRef::as_key_ref(&$ata);
186        let __real_ata = $crate::ata::get_associated_token_address(
187            $crate::AsKeyRef::as_key_ref(&$owner),
188            $crate::AsKeyRef::as_key_ref(&$mint),
189        );
190        if &__real_ata != __ata {
191            msg!(
192                "ATA mismatch: {}: {} (left) != {} (right)",
193                $msg,
194                __ata,
195                __real_ata
196            );
197            msg!("Owner: {}", $crate::AsKeyRef::as_key_ref(&$owner));
198            msg!("Mint: {}", $crate::AsKeyRef::as_key_ref(&$mint));
199            $crate::throw_err!($crate::VipersError::ATAMismatch);
200        }
201    }};
202}
203
204/// Asserts that the given [anchor_spl::token::TokenAccount] is an associated token account.
205///
206/// Warning: this uses a lot of compute units due to the need to generate a PDA.
207/// Use this macro sparingly.
208#[macro_export]
209macro_rules! assert_is_ata {
210    ($ata: expr $(,)?) => {
211        $crate::assert_ata!($ata, "invalid ata")
212    };
213    ($ata: expr, $msg: expr $(,)?) => {{
214        $crate::assert_owner!($ata, token, "ATA not owned by token program");
215        let __owner = $ata.owner;
216        let __mint = $ata.mint;
217        let __ata = anchor_lang::Key::key(&$ata);
218        let __real_ata =
219            $crate::spl_associated_token_account::get_associated_token_address(&__owner, &__mint);
220        if __real_ata != __ata {
221            msg!(
222                "Invalid ATA: {}: {} (left) != {} (right)",
223                $msg,
224                __ata,
225                __real_ata
226            );
227            msg!("Owner: {}", __owner);
228            msg!("Mint: {}", __mint);
229            $crate::throw_err!($crate::VipersError::InvalidATA);
230        }
231    }};
232}
233
234/// Asserts that an account is owned by the given program.
235///
236/// As of Anchor 0.15, Anchor handles this for you automatically.
237/// You should not need to use this.
238#[macro_export]
239#[deprecated(
240    since = "1.5.6",
241    note = "As of Anchor 0.15, Anchor handles this for you automatically."
242)]
243macro_rules! assert_owner {
244    ($program_account: expr, $owner: expr $(,)?) => {
245        $crate::assert_owner!($program_account, $owner, "owner mismatch")
246    };
247    ($program_account: expr, $owner: ident $(,)?) => {
248        $crate::assert_owner!($program_account, $owner);
249    };
250    ($program_account: expr, $owner: ident, $msg: expr $(,)?) => {
251        let __program_id = $crate::program_ids::$owner::ID;
252        $crate::assert_owner!($program_account, $owner, $msg);
253    };
254    ($program_account: expr, $owner: expr, $msg: expr $(,)?) => {{
255        let __program_account =
256            anchor_lang::ToAccountInfo::to_account_info(&$program_account).owner;
257        let __owner = $crate::AsKeyRef::as_key_ref(&$owner);
258        if __program_account != __owner {
259            msg!(
260                "Owner mismatch: {}: expected {}, got {}",
261                $msg,
262                __program_account,
263                __owner
264            );
265            return Err($crate::VipersError::OwnerMismatch.into());
266        }
267    }};
268}
269
270/// Asserts that two accounts share the same key.
271///
272/// # Example
273///
274/// ```should_panic
275/// # use anchor_lang::prelude::*;
276/// # #[error_code]
277/// # pub enum ErrorCode { MyError }
278/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
279/// let one = anchor_lang::solana_program::sysvar::clock::ID;
280/// let two = anchor_lang::solana_program::system_program::ID;
281/// assert_keys_eq!(one, two); // throws an error
282/// Ok(())
283/// # }
284/// ```
285///
286/// ```should_panic
287/// # use anchor_lang::prelude::*;
288/// # #[error_code]
289/// # pub enum ErrorCode { MyError }
290/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
291/// let one = anchor_lang::solana_program::sysvar::clock::ID;
292/// let two = anchor_lang::solana_program::system_program::ID;
293/// assert_keys_eq!(one, two, "invalid"); // throws an error
294/// # Ok(())
295/// # }
296/// ```
297#[macro_export]
298macro_rules! assert_keys_eq {
299    ($account_a: expr, $account_b: expr $(,)?) => {
300        $crate::assert_keys_eq!($account_a, $account_b, $crate::VipersError::KeyMismatch);
301    };
302    ($account_a: expr, $account_b: expr, $err_code: ident $(,)?) => {
303        $crate::assert_keys_eq!($account_a, $account_b, crate::ErrorCode::$err_code);
304    };
305    ($account_a: expr, $account_b: expr, $msg: literal $(,)?) => {
306        $crate::assert_keys_eq!(
307            $account_a,
308            $account_b,
309            $crate::VipersError::KeyMismatch,
310            &*format!("Key mismatch: {}", $msg),
311        );
312    };
313    ($account_a: expr, $account_b: expr, $err: expr $(,)?) => {
314        $crate::assert_keys_eq!($account_a, $account_b, $err, $crate::format_err!($err));
315    };
316    ($account_a: expr, $account_b: expr, $err: expr, $msg: expr $(,)?) => {{
317        let __key_a = &$account_a;
318        let __key_b = &$account_b;
319        let __account_a = $crate::AsKeyRef::as_key_ref(__key_a);
320        let __account_b = $crate::AsKeyRef::as_key_ref(__key_b);
321        if __account_a != __account_b {
322            msg!($msg);
323            msg!(stringify!($account_a != $account_b));
324            msg!("Left: {}", __account_a);
325            msg!("Right: {}", __account_b);
326            $crate::throw_err!($err);
327        }
328    }};
329}
330
331/// Asserts that a token account is "zero".
332///
333/// This means that:
334/// - the `amount` is zero
335/// - the `delegate` is `None`
336/// - the `close_authority` is `None`
337///
338/// This is useful for checking to see that a bad actor cannot
339/// modify PDA-owned token accounts.
340///
341/// # Example
342///
343/// ```
344/// # #[macro_use] extern crate tensor_vipers;
345/// # use anchor_lang::prelude::*;
346/// # use anchor_spl::token::*;
347/// #[error_code]
348/// pub enum ErrorCode { MyError }
349///
350/// # fn main() {
351///
352/// let mut zero_account = spl_token::state::Account::default();
353/// assert_does_not_throw!({
354///   assert_is_zero_token_account!(zero_account);
355/// });
356///
357/// let mut non_zero_account = spl_token::state::Account::default();
358/// non_zero_account.amount = 10;
359/// assert_throws!({
360///   assert_is_zero_token_account!(non_zero_account);
361/// }, tensor_vipers::VipersError::TokenAccountIsNonZero);
362///
363/// non_zero_account = spl_token::state::Account::default();
364/// non_zero_account.delegate = spl_token::ID.into();
365/// assert_throws!({
366///   assert_is_zero_token_account!(non_zero_account);
367/// }, tensor_vipers::VipersError::TokenAccountIsNonZero);
368///
369/// non_zero_account = spl_token::state::Account::default();
370/// non_zero_account.close_authority = spl_token::ID.into();
371/// assert_throws!({
372///   assert_is_zero_token_account!(non_zero_account);
373/// }, tensor_vipers::VipersError::TokenAccountIsNonZero);
374/// # }
375/// ```
376#[macro_export]
377macro_rules! assert_is_zero_token_account {
378    ($token_account: expr $(,)?) => {
379        $crate::assert_is_zero_token_account!(
380            $token_account,
381            $crate::VipersError::TokenAccountIsNonZero
382        );
383    };
384    ($token_account: expr, $err_code: ident $(,)?) => {
385        $crate::assert_is_zero_token_account!($token_account, crate::ErrorCode::$err_code);
386    };
387    ($token_account: expr, $msg: literal $(,)?) => {
388        $crate::assert_is_zero_token_account!(
389            $token_account,
390            $crate::VipersError::TokenAccountIsNonZero,
391            &*format!("Token account is non-zero: {}", $msg),
392        );
393    };
394    ($token_account: expr, $err: expr $(,)?) => {
395        $crate::assert_is_zero_token_account!($token_account, $err, $crate::format_err!($err));
396    };
397    ($token_account: expr, $err: expr, $msg: expr $(,)?) => {{
398        $crate::invariant!(
399            $token_account.amount == 0
400                && $token_account.delegate.is_none()
401                && $token_account.close_authority.is_none(),
402            $err,
403            $msg
404        );
405    }};
406}
407
408/// Asserts that two accounts do not share the same key.
409///
410/// # Example
411///
412/// ```should_panic
413/// # use anchor_lang::prelude::*;
414/// # impl From<ErrorCode> for ProgramError { fn from(code: ErrorCode) -> Self { ProgramError::Custom(10) } }
415/// # pub enum ErrorCode { MyError }
416/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
417/// let one = Pubkey::default();
418/// let two = Pubkey::default();
419/// assert_keys_neq!(one, two); // throws an error
420/// # Ok(())
421/// # }
422/// ```
423#[macro_export]
424macro_rules! assert_keys_neq {
425    ($account_a: expr, $account_b: expr $(,)?) => {
426        $crate::assert_keys_neq!(
427            $account_a,
428            $account_b,
429            $crate::VipersError::KeysMustNotMatch
430        );
431    };
432    ($account_a: expr, $account_b: expr, $err_code: ident $(,)?) => {
433        $crate::assert_keys_neq!($account_a, $account_b, crate::ErrorCode::$err_code);
434    };
435    ($account_a: expr, $account_b: expr, $msg: literal $(,)?) => {
436        $crate::assert_keys_neq!(
437            $account_a,
438            $account_b,
439            $crate::VipersError::KeysMustNotMatch,
440            &*format!("Keys must not match: {}", $msg),
441        );
442    };
443    ($account_a: expr, $account_b: expr, $err: expr $(,)?) => {
444        $crate::assert_keys_neq!($account_a, $account_b, $err, $crate::format_err!($err));
445    };
446    ($account_a: expr, $account_b: expr, $err: expr, $msg: expr $(,)?) => {{
447        let __key_a = &$account_a;
448        let __key_b = &$account_b;
449        let __account_a = $crate::AsKeyRef::as_key_ref(__key_a);
450        let __account_b = $crate::AsKeyRef::as_key_ref(__key_b);
451        if __account_a == __account_b {
452            msg!($msg);
453            msg!(stringify!($account_a == $account_b));
454            msg!("Left: {}", __account_a);
455            msg!("Right: {}", __account_b);
456            $crate::throw_err!($err);
457        }
458    }};
459}
460
461/// Ensures an [Option] can be unwrapped, otherwise returns the error.
462///
463/// # Example
464///
465/// ```should_panic
466/// # use anchor_lang::prelude::*;
467/// # impl From<ErrorCode> for ProgramError { fn from(code: ErrorCode) -> Self { ProgramError::Custom(10) } }
468/// # pub enum ErrorCode { MyError }
469/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
470/// let one = 1_u64;
471/// let two = 2_u64;
472/// let my_value = unwrap_or_err!(one.checked_sub(2), MyError); // throws an error
473/// Ok(())
474/// # }
475/// ```
476#[macro_export]
477macro_rules! unwrap_or_err {
478    ($option:expr, $error:ident $(,)?) => {
479        $option.ok_or_else(|| -> ProgramError { crate::ErrorCode::$error.into() })?
480    };
481}
482
483/// Unwraps the result of a checked integer operation.
484///
485/// # Example
486///
487/// ```should_panic
488/// # use anchor_lang::prelude::*;
489/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
490/// let one = 1_u64;
491/// let two = 2_u64;
492/// let my_value = unwrap_int!(one.checked_sub(2)); // returns an error
493/// Ok(())
494/// # }
495/// ```
496#[macro_export]
497macro_rules! unwrap_int {
498    ($option:expr $(,)?) => {
499        $crate::unwrap_opt!($option, $crate::VipersError::IntegerOverflow)
500    };
501}
502
503/// Unwraps a bump seed.
504///
505/// # Example
506///
507/// ```ignore
508/// # use anchor_lang::prelude::*;
509/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
510/// fn my_instruction(ctx: Context<MyAccounts>) -> Result<()> {
511///     let my_data = &mut ctx.accounts.my_data
512///     my_data.bump = unwrap_bump!(ctx, "my_data");
513///     Ok(())
514/// }
515/// # }
516/// ```
517#[macro_export]
518macro_rules! unwrap_bump {
519    ($ctx:expr, $bump:literal $(,)?) => {
520        *$crate::unwrap_opt!(
521            $ctx.bumps.get($bump),
522            $crate::VipersError::UnknownBump,
523            format!("Unknown bump: {}", $bump)
524        )
525    };
526}
527
528/// Tries to unwrap the [Result], otherwise returns the error
529///
530/// # Example
531///
532/// ```should_panic
533/// # use anchor_lang::prelude::*;
534/// # #[error_code]
535/// # pub enum ErrorCode { MyError }
536/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
537/// fn function_returning_result() -> Result<u64> {
538///     err!(ErrorCode::MyError)
539/// }
540///
541/// let my_value = try_or_err!(function_returning_result(), ErrorCode::MyError);
542/// # Ok(()) }
543/// ```
544
545//fixed up to make it work with anchor 0.26x
546#[macro_export]
547macro_rules! try_or_err {
548    ($result:expr, $error:expr $(,)?) => {
549        $result.map_err(|_| $error)?
550    };
551}
552
553/// Asserts that an invariant holds, otherwise logs the given message.
554/// This is a drop-in replacement for `require!`.
555///
556/// # Example
557///
558/// ```should_panic
559/// # use anchor_lang::prelude::*;
560/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
561/// invariant!(1 == 2, "incorrect");
562/// # Ok(()) }
563/// ```
564///
565/// Invariants do not throw if they pass.
566///
567/// ```
568/// # use anchor_lang::prelude::*;
569/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
570/// invariant!(1 == 1, "won't throw");
571/// # Ok(()) }
572/// ```
573///
574/// Error codes are optional:
575///
576/// ```
577/// # use anchor_lang::prelude::*;
578/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
579/// invariant!(1 == 1);
580/// # Ok(()) }
581/// ```
582///
583/// You may also use a crate ErrorCode:
584///
585/// ```
586/// # #[macro_use] extern crate tensor_vipers;
587/// # use anchor_lang::prelude::*;
588/// #[error_code]
589/// pub enum ErrorCode { MyError }
590///
591/// # fn main() {
592/// assert_does_not_throw!({
593///   invariant!(1 == 1, MyError);
594/// });
595/// assert_throws!({
596///   invariant!(1 == 2);
597/// }, tensor_vipers::VipersError::InvariantFailed);
598/// assert_throws!({
599///   invariant!(1 == 2, "this is stupid");
600/// }, tensor_vipers::VipersError::InvariantFailed);
601/// assert_throws!({
602///   invariant!(1 == 2, MyError);
603/// }, ErrorCode::MyError);
604/// assert_throws!({
605///   invariant!(1 == 2, MyError);
606/// }, ErrorCode::MyError);
607/// assert_throws!({
608///   invariant!(1 == 2, MyError, "this is wack");
609/// }, ErrorCode::MyError);
610/// # }
611/// ```
612#[macro_export]
613macro_rules! invariant {
614    ($invariant: expr $(,)?) => {
615        $crate::invariant!($invariant, $crate::VipersError::InvariantFailed);
616    };
617    ($invariant: expr, $err_code: ident $(,)?) => {
618        $crate::invariant!($invariant, crate::ErrorCode::$err_code);
619    };
620    ($invariant: expr, $err_code: ident, $msg: expr $(,)?) => {
621        $crate::invariant!($invariant, crate::ErrorCode::$err_code, $msg);
622    };
623    ($invariant: expr, $msg: literal $(,)?) => {
624        $crate::invariant!(
625            $invariant,
626            $crate::VipersError::InvariantFailed,
627            &*format!("Invariant failed: {}", $msg)
628        );
629    };
630    ($invariant:expr, $err:expr $(,)?) => {
631        $crate::invariant!($invariant, $err, $crate::format_err!($err));
632    };
633    ($invariant:expr, $err:expr, $msg: expr $(,)?) => {{
634        if !($invariant) {
635            msg!($msg);
636            msg!(stringify!($invariant));
637            $crate::throw_err!($err);
638        }
639    }};
640}
641
642/// Attempts to unwrap an [Option], and if it fails, prints an error.
643///
644/// # Example
645///
646/// ```should_panic
647/// # use anchor_lang::prelude::*;
648/// # #[macro_use] extern crate tensor_vipers; fn main() -> Result<()> {
649/// let one = 1_u64;
650/// let two = 2_u64;
651/// let my_value = unwrap_opt!(one.checked_sub(2), "cannot do this"); // returns an error
652/// # Ok(()) }
653/// ```
654#[macro_export]
655macro_rules! unwrap_opt {
656    ($option: expr $(,)?) => {
657        $crate::unwrap_opt!(
658            $option,
659            $crate::VipersError::OptionUnwrapFailed,
660            $crate::format_err!($crate::VipersError::OptionUnwrapFailed)
661        )
662    };
663    ($option: expr, $err_code: ident $(,)?) => {
664        $crate::unwrap_opt!($option, crate::ErrorCode::$err_code)
665    };
666    ($option: expr, $msg: literal $(,)?) => {
667        $crate::unwrap_opt!($option, $crate::VipersError::OptionUnwrapFailed, $msg)
668    };
669    ($option:expr, $err:expr $(,)?) => {
670        $crate::unwrap_opt!($option, $err, $crate::format_err!($err))
671    };
672    ($option:expr, $err:expr, $msg: expr $(,)?) => {
673        $option.ok_or_else(|| -> anchor_lang::error::Error {
674            msg!("Option unwrap failed: {:?}", $err);
675            msg!(stringify!($option));
676            $crate::log_code_location!();
677            anchor_lang::prelude::error!($err)
678        })?
679    };
680}
681
682/// Asserts that two accounts share the same key.
683///
684/// Deprecated in favor of [assert_keys_eq].
685#[deprecated]
686#[macro_export]
687macro_rules! assert_keys {
688    ($account_a: expr, $account_b: expr $(,)?) => {
689        $crate::assert_keys_eq!($account_a, $account_b, "key mismatch")
690    };
691    ($account_a: expr, $account_b: expr, $msg: expr $(,)?) => {
692        $crate::assert_keys_eq!($account_a, $account_b, $msg)
693    };
694}