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}