Browse Source

lang: allow `token::...` and `mint::...` to be used as checks without init (#1505)

Co-authored-by: Paul Schaaf <paulsimonschaaf@gmail.com>
Anan 3 years ago
parent
commit
f5dffe6490

+ 6 - 4
lang/derive/accounts/src/lib.rs

@@ -436,8 +436,9 @@ use syn::parse_macro_input;
 ///                 <code>#[account(token::mint = &lt;target_account&gt;, token::authority = &lt;target_account&gt;)]</code>
 ///                 <code>#[account(token::mint = &lt;target_account&gt;, token::authority = &lt;target_account&gt;)]</code>
 ///             </td>
 ///             </td>
 ///             <td>
 ///             <td>
-///                 Can currently only be used with <code>init</code> to create a token
-///                 account with the given mint address and authority.
+///                 Can be used as a check or with <code>init</code> to create a token
+///                 account with the given mint address and authority.<br>
+///                  When used as a check, it's possible to only specify a subset of the constraints.
 ///                 <br><br>
 ///                 <br><br>
 ///                 Example:
 ///                 Example:
 ///                 <pre>
 ///                 <pre>
@@ -466,9 +467,10 @@ use syn::parse_macro_input;
 ///                 <code>#[account(mint::authority = &lt;target_account&gt;, mint::decimals = &lt;expr&gt;, mint::freeze_authority = &lt;target_account&gt;)]</code>
 ///                 <code>#[account(mint::authority = &lt;target_account&gt;, mint::decimals = &lt;expr&gt;, mint::freeze_authority = &lt;target_account&gt;)]</code>
 ///             </td>
 ///             </td>
 ///             <td>
 ///             <td>
-///                 Can currently only be used with <code>init</code> to create a mint
+///                 Can be used as a check or with <code>init</code> to create a mint
 ///                 account with the given mint decimals and mint authority.<br>
 ///                 account with the given mint decimals and mint authority.<br>
-///                 The freeze authority is optional.
+///                 The freeze authority is optional when used with <code>init</code>.<br>
+///                 When used as a check, it's possible to only specify a subset of the constraints.
 ///                 <br><br>
 ///                 <br><br>
 ///                 Example:
 ///                 Example:
 ///                 <pre>
 ///                 <pre>

+ 67 - 0
lang/syn/src/codegen/accounts/constraints.rs

@@ -57,6 +57,8 @@ pub fn linearize(c_group: &ConstraintGroup) -> Vec<Constraint> {
         close,
         close,
         address,
         address,
         associated_token,
         associated_token,
+        token_account,
+        mint,
     } = c_group.clone();
     } = c_group.clone();
 
 
     let mut constraints = Vec::new();
     let mut constraints = Vec::new();
@@ -100,6 +102,12 @@ pub fn linearize(c_group: &ConstraintGroup) -> Vec<Constraint> {
     if let Some(c) = address {
     if let Some(c) = address {
         constraints.push(Constraint::Address(c));
         constraints.push(Constraint::Address(c));
     }
     }
+    if let Some(c) = token_account {
+        constraints.push(Constraint::TokenAccount(c));
+    }
+    if let Some(c) = mint {
+        constraints.push(Constraint::Mint(c));
+    }
     constraints
     constraints
 }
 }
 
 
@@ -120,6 +128,8 @@ fn generate_constraint(f: &Field, c: &Constraint) -> proc_macro2::TokenStream {
         Constraint::Close(c) => generate_constraint_close(f, c),
         Constraint::Close(c) => generate_constraint_close(f, c),
         Constraint::Address(c) => generate_constraint_address(f, c),
         Constraint::Address(c) => generate_constraint_address(f, c),
         Constraint::AssociatedToken(c) => generate_constraint_associated_token(f, c),
         Constraint::AssociatedToken(c) => generate_constraint_associated_token(f, c),
+        Constraint::TokenAccount(c) => generate_constraint_token_account(f, c),
+        Constraint::Mint(c) => generate_constraint_mint(f, c),
     }
     }
 }
 }
 
 
@@ -682,6 +692,63 @@ fn generate_constraint_associated_token(
     }
     }
 }
 }
 
 
+fn generate_constraint_token_account(
+    f: &Field,
+    c: &ConstraintTokenAccountGroup,
+) -> proc_macro2::TokenStream {
+    let name = &f.ident;
+    let authority_check = match &c.authority {
+        Some(authority) => {
+            quote! { if #name.owner != #authority.key() { return Err(anchor_lang::error::ErrorCode::ConstraintTokenOwner.into()); } }
+        }
+        None => quote! {},
+    };
+    let mint_check = match &c.mint {
+        Some(mint) => {
+            quote! { if #name.mint != #mint.key() { return Err(anchor_lang::error::ErrorCode::ConstraintTokenMint.into()); } }
+        }
+        None => quote! {},
+    };
+    quote! {
+        #authority_check
+        #mint_check
+    }
+}
+
+fn generate_constraint_mint(f: &Field, c: &ConstraintTokenMintGroup) -> proc_macro2::TokenStream {
+    let name = &f.ident;
+
+    let decimal_check = match &c.decimals {
+        Some(decimals) => quote! {
+            if #name.decimals != #decimals {
+                return Err(anchor_lang::error::ErrorCode::ConstraintMintDecimals.into());
+            }
+        },
+        None => quote! {},
+    };
+    let mint_authority_check = match &c.mint_authority {
+        Some(mint_authority) => quote! {
+            if #name.mint_authority != anchor_lang::solana_program::program_option::COption::Some(anchor_lang::Key::key(&#mint_authority)) {
+                return Err(anchor_lang::error::ErrorCode::ConstraintMintMintAuthority.into());
+            }
+        },
+        None => quote! {},
+    };
+    let freeze_authority_check = match &c.freeze_authority {
+        Some(freeze_authority) => quote! {
+            if #name.freeze_authority != anchor_lang::solana_program::program_option::COption::Some(anchor_lang::Key::key(&#freeze_authority)) {
+                return Err(anchor_lang::error::ErrorCode::ConstraintMintFreezeAuthority.into());
+            }
+        },
+        None => quote! {},
+    };
+    quote! {
+        #decimal_check
+        #mint_authority_check
+        #freeze_authority_check
+    }
+}
+
 // Generated code to create an account with with system program with the
 // Generated code to create an account with with system program with the
 // given `space` amount of data, owned by `owner`.
 // given `space` amount of data, owned by `owner`.
 //
 //

+ 17 - 0
lang/syn/src/lib.rs

@@ -587,6 +587,8 @@ pub struct ConstraintGroup {
     close: Option<ConstraintClose>,
     close: Option<ConstraintClose>,
     address: Option<ConstraintAddress>,
     address: Option<ConstraintAddress>,
     associated_token: Option<ConstraintAssociatedToken>,
     associated_token: Option<ConstraintAssociatedToken>,
+    token_account: Option<ConstraintTokenAccountGroup>,
+    mint: Option<ConstraintTokenMintGroup>,
 }
 }
 
 
 impl ConstraintGroup {
 impl ConstraintGroup {
@@ -628,6 +630,8 @@ pub enum Constraint {
     State(ConstraintState),
     State(ConstraintState),
     Close(ConstraintClose),
     Close(ConstraintClose),
     Address(ConstraintAddress),
     Address(ConstraintAddress),
+    TokenAccount(ConstraintTokenAccountGroup),
+    Mint(ConstraintTokenMintGroup),
 }
 }
 
 
 // Constraint token is a single keyword in a `#[account(<TOKEN>)]` attribute.
 // Constraint token is a single keyword in a `#[account(<TOKEN>)]` attribute.
@@ -832,6 +836,19 @@ pub struct ConstraintAssociatedToken {
     pub mint: Expr,
     pub mint: Expr,
 }
 }
 
 
+#[derive(Debug, Clone)]
+pub struct ConstraintTokenAccountGroup {
+    pub mint: Option<Expr>,
+    pub authority: Option<Expr>,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintTokenMintGroup {
+    pub decimals: Option<Expr>,
+    pub mint_authority: Option<Expr>,
+    pub freeze_authority: Option<Expr>,
+}
+
 // Syntaxt context object for preserving metadata about the inner item.
 // Syntaxt context object for preserving metadata about the inner item.
 #[derive(Debug, Clone)]
 #[derive(Debug, Clone)]
 pub struct Context<T> {
 pub struct Context<T> {

+ 105 - 73
lang/syn/src/parser/accounts/constraints.rs

@@ -424,6 +424,42 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
                     ));
                     ));
                 }
                 }
             }
             }
+
+            // TokenAccount.
+            if let Some(token_mint) = &self.token_mint {
+                if self.token_authority.is_none() {
+                    return Err(ParseError::new(
+                        token_mint.span(),
+                        "when initializing, token authority must be provided if token mint is",
+                    ));
+                }
+            }
+            if let Some(token_authority) = &self.token_authority {
+                if self.token_mint.is_none() {
+                    return Err(ParseError::new(
+                        token_authority.span(),
+                        "when initializing, token mint must be provided if token authority is",
+                    ));
+                }
+            }
+
+            // Mint.
+            if let Some(mint_decimals) = &self.mint_decimals {
+                if self.mint_authority.is_none() {
+                    return Err(ParseError::new(
+                        mint_decimals.span(),
+                        "when initializing, mint authority must be provided if mint decimals is",
+                    ));
+                }
+            }
+            if let Some(mint_authority) = &self.mint_authority {
+                if self.mint_decimals.is_none() {
+                    return Err(ParseError::new(
+                        mint_authority.span(),
+                        "when initializing, mint decimals must be provided if mint authority is",
+                    ));
+                }
+            }
         }
         }
 
 
         // Zero.
         // Zero.
@@ -462,49 +498,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             }
             }
         }
         }
 
 
-        // Token.
-        if let Some(token_mint) = &self.token_mint {
-            if self.token_authority.is_none() {
-                return Err(ParseError::new(
-                    token_mint.span(),
-                    "token authority must be provided if token mint is",
-                ));
-            }
-
-            if self.init.is_none() {
-                return Err(ParseError::new(
-                    token_mint.span(),
-                    "init is required for a pda token",
-                ));
-            }
-        }
-        if let Some(token_authority) = &self.token_authority {
-            if self.token_mint.is_none() {
-                return Err(ParseError::new(
-                    token_authority.span(),
-                    "token mint must be provided if token authority is",
-                ));
-            }
-        }
-
-        // Mint.
-        if let Some(mint_decimals) = &self.mint_decimals {
-            if self.mint_authority.is_none() {
-                return Err(ParseError::new(
-                    mint_decimals.span(),
-                    "mint authority must be provided if mint decimals is",
-                ));
-            }
-        }
-        if let Some(mint_authority) = &self.mint_authority {
-            if self.mint_decimals.is_none() {
-                return Err(ParseError::new(
-                    mint_authority.span(),
-                    "mint decimals must be provided if mint authority is",
-                ));
-            }
-        }
-
         // Space.
         // Space.
         if let Some(i) = &self.init {
         if let Some(i) = &self.init {
             let initializing_token_program_acc = self.token_mint.is_some()
             let initializing_token_program_acc = self.token_mint.is_some()
@@ -600,6 +593,31 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             }
             }
             _ => None,
             _ => None,
         };
         };
+        let token_account = match (&token_mint, &token_authority) {
+            (None, None) => None,
+            _ => Some(ConstraintTokenAccountGroup {
+                mint: token_mint.as_ref().map(|a| a.clone().into_inner().mint),
+                authority: token_authority
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().auth),
+            }),
+        };
+
+        let mint = match (&mint_decimals, &mint_authority, &mint_freeze_authority) {
+            (None, None, None) => None,
+            _ => Some(ConstraintTokenMintGroup {
+                decimals: mint_decimals
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().decimals),
+                mint_authority: mint_authority
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().mint_auth),
+                freeze_authority: mint_freeze_authority
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().mint_freeze_auth),
+            }),
+        };
+
         Ok(ConstraintGroup {
         Ok(ConstraintGroup {
             init: init.as_ref().map(|i| Ok(ConstraintInitGroup {
             init: init.as_ref().map(|i| Ok(ConstraintInitGroup {
                 if_needed: i.if_needed,
                 if_needed: i.if_needed,
@@ -654,6 +672,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             address: into_inner!(address),
             address: into_inner!(address),
             associated_token: if !is_init { associated_token } else { None },
             associated_token: if !is_init { associated_token } else { None },
             seeds,
             seeds,
+            token_account: if !is_init {token_account} else {None},
+            mint: if !is_init {mint} else {None},
         })
         })
     }
     }
 
 
@@ -694,6 +714,48 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
         if self.zeroed.is_some() {
         if self.zeroed.is_some() {
             return Err(ParseError::new(c.span(), "zeroed already provided"));
             return Err(ParseError::new(c.span(), "zeroed already provided"));
         }
         }
+        if self.token_mint.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "init must be provided before token mint",
+            ));
+        }
+        if self.token_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "init must be provided before token authority",
+            ));
+        }
+        if self.mint_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "init must be provided before mint authority",
+            ));
+        }
+        if self.mint_freeze_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "init must be provided before mint freeze authority",
+            ));
+        }
+        if self.mint_decimals.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "init must be provided before mint decimals",
+            ));
+        }
+        if self.associated_token_mint.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "init must be provided before associated token mint",
+            ));
+        }
+        if self.associated_token_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "init must be provided before associated token authority",
+            ));
+        }
         self.init.replace(c);
         self.init.replace(c);
         Ok(())
         Ok(())
     }
     }
@@ -751,12 +813,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
                 "associated token mint already provided",
                 "associated token mint already provided",
             ));
             ));
         }
         }
-        if self.init.is_none() {
-            return Err(ParseError::new(
-                c.span(),
-                "init must be provided before token",
-            ));
-        }
         self.token_mint.replace(c);
         self.token_mint.replace(c);
         Ok(())
         Ok(())
     }
     }
@@ -823,12 +879,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
                 "token authority already provided",
                 "token authority already provided",
             ));
             ));
         }
         }
-        if self.init.is_none() {
-            return Err(ParseError::new(
-                c.span(),
-                "init must be provided before token authority",
-            ));
-        }
         self.token_authority.replace(c);
         self.token_authority.replace(c);
         Ok(())
         Ok(())
     }
     }
@@ -857,12 +907,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
         if self.mint_authority.is_some() {
         if self.mint_authority.is_some() {
             return Err(ParseError::new(c.span(), "mint authority already provided"));
             return Err(ParseError::new(c.span(), "mint authority already provided"));
         }
         }
-        if self.init.is_none() {
-            return Err(ParseError::new(
-                c.span(),
-                "init must be provided before mint authority",
-            ));
-        }
         self.mint_authority.replace(c);
         self.mint_authority.replace(c);
         Ok(())
         Ok(())
     }
     }
@@ -877,12 +921,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
                 "mint freeze_authority already provided",
                 "mint freeze_authority already provided",
             ));
             ));
         }
         }
-        if self.init.is_none() {
-            return Err(ParseError::new(
-                c.span(),
-                "init must be provided before mint freeze_authority",
-            ));
-        }
         self.mint_freeze_authority.replace(c);
         self.mint_freeze_authority.replace(c);
         Ok(())
         Ok(())
     }
     }
@@ -891,12 +929,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
         if self.mint_decimals.is_some() {
         if self.mint_decimals.is_some() {
             return Err(ParseError::new(c.span(), "mint decimals already provided"));
             return Err(ParseError::new(c.span(), "mint decimals already provided"));
         }
         }
-        if self.init.is_none() {
-            return Err(ParseError::new(
-                c.span(),
-                "init must be provided before mint decimals",
-            ));
-        }
         self.mint_decimals.replace(c);
         self.mint_decimals.replace(c);
         Ok(())
         Ok(())
     }
     }

+ 104 - 4
tests/misc/programs/misc/src/context.rs

@@ -16,7 +16,6 @@ pub struct TestTokenSeedsInit<'info> {
         payer = authority,
         payer = authority,
         mint::decimals = 6,
         mint::decimals = 6,
         mint::authority = authority,
         mint::authority = authority,
-        
     )]
     )]
     pub mint: Account<'info, Mint>,
     pub mint: Account<'info, Mint>,
     #[account(
     #[account(
@@ -26,7 +25,6 @@ pub struct TestTokenSeedsInit<'info> {
         payer = authority,
         payer = authority,
         token::mint = mint,
         token::mint = mint,
         token::authority = authority,
         token::authority = authority,
-        
     )]
     )]
     pub my_pda: Account<'info, TokenAccount>,
     pub my_pda: Account<'info, TokenAccount>,
     #[account(mut)]
     #[account(mut)]
@@ -41,10 +39,9 @@ pub struct TestTokenSeedsInit<'info> {
 pub struct TestInitAssociatedToken<'info> {
 pub struct TestInitAssociatedToken<'info> {
     #[account(
     #[account(
         init,
         init,
-        payer = payer,
         associated_token::mint = mint,
         associated_token::mint = mint,
+        payer = payer,
         associated_token::authority = payer,
         associated_token::authority = payer,
-        
     )]
     )]
     pub token: Account<'info, TokenAccount>,
     pub token: Account<'info, TokenAccount>,
     pub mint: Account<'info, Mint>,
     pub mint: Account<'info, Mint>,
@@ -476,3 +473,106 @@ pub struct TestUnsafeFieldSafetyErrors<'info> {
     pub signer: Signer<'info>,
     pub signer: Signer<'info>,
     pub system_program: Program<'info, System>,
     pub system_program: Program<'info, System>,
 }
 }
+
+#[derive(Accounts)]
+pub struct TestConstraintToken<'info> {
+    #[account(
+        token::mint = mint,
+        token::authority = payer
+    )]
+    pub token: Account<'info, TokenAccount>,
+    pub mint: Account<'info, Mint>,
+    pub payer: Signer<'info>,
+}
+
+#[derive(Accounts)]
+pub struct TestAuthorityConstraint<'info> {
+    #[account(
+        token::mint = mint,
+        token::authority = fake_authority
+    )]
+    pub token: Account<'info, TokenAccount>,
+    pub mint: Account<'info, Mint>,
+    pub fake_authority: AccountInfo<'info>,
+}
+#[derive(Accounts)]
+pub struct TestOnlyAuthorityConstraint<'info> {
+    #[account(
+        token::authority = payer
+    )]
+    pub token: Account<'info, TokenAccount>,
+    pub mint: Account<'info, Mint>,
+    pub payer: Signer<'info>,
+}
+#[derive(Accounts)]
+pub struct TestOnlyMintConstraint<'info> {
+    #[account(
+        token::mint = mint,
+    )]
+    pub token: Account<'info, TokenAccount>,
+    pub mint: Account<'info, Mint>,
+}
+
+#[derive(Accounts)]
+#[instruction(decimals: u8)]
+pub struct TestMintConstraint<'info> {
+    #[account(
+        mint::decimals = decimals,
+        mint::authority = mint_authority,
+        mint::freeze_authority = freeze_authority
+    )]
+    pub mint: Account<'info, Mint>,
+    pub mint_authority: AccountInfo<'info>,
+    pub freeze_authority: AccountInfo<'info>,
+}
+
+#[derive(Accounts)]
+#[instruction(decimals: u8)]
+pub struct TestMintOnlyDecimalsConstraint<'info> {
+    #[account(
+        mint::decimals = decimals,
+    )]
+    pub mint: Account<'info, Mint>,
+}
+
+#[derive(Accounts)]
+pub struct TestMintAuthorityConstraint<'info> {
+    #[account(
+        mint::authority = mint_authority,
+        mint::freeze_authority = freeze_authority
+    )]
+    pub mint: Account<'info, Mint>,
+    pub mint_authority: AccountInfo<'info>,
+    pub freeze_authority: AccountInfo<'info>,
+}
+
+#[derive(Accounts)]
+pub struct TestMintOneAuthorityConstraint<'info> {
+    #[account(
+        mint::authority = mint_authority,
+    )]
+    pub mint: Account<'info, Mint>,
+    pub mint_authority: AccountInfo<'info>,
+}
+
+#[derive(Accounts)]
+#[instruction(decimals: u8)]
+pub struct TestMintMissMintAuthConstraint<'info> {
+    #[account(
+        mint::decimals = decimals,
+        mint::freeze_authority = freeze_authority,
+    )]
+    pub mint: Account<'info, Mint>,
+    pub freeze_authority: AccountInfo<'info>,
+}
+
+#[derive(Accounts)]
+pub struct TestAssociatedToken<'info> {
+    #[account(
+        associated_token::mint = mint,
+        associated_token::authority = authority,
+    )]
+    pub token: Account<'info, TokenAccount>,
+    pub mint: Account<'info, Mint>,
+    pub authority: AccountInfo<'info>,
+}

+ 50 - 0
tests/misc/programs/misc/src/lib.rs

@@ -303,4 +303,54 @@ pub mod misc {
     ) -> Result<()> {
     ) -> Result<()> {
         Ok(())
         Ok(())
     }
     }
+
+    pub fn test_token_constraint(_ctx: Context<TestConstraintToken>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_token_auth_constraint(_ctx: Context<TestAuthorityConstraint>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_only_auth_constraint(_ctx: Context<TestOnlyAuthorityConstraint>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_only_mint_constraint(_ctx: Context<TestOnlyMintConstraint>) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_mint_constraint(_ctx: Context<TestMintConstraint>, _decimals: u8) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_mint_only_decimals_constraint(
+        _ctx: Context<TestMintOnlyDecimalsConstraint>,
+        _decimals: u8,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_mint_only_auth_constraint(
+        _ctx: Context<TestMintAuthorityConstraint>,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_mint_only_one_auth_constraint(
+        _ctx: Context<TestMintOneAuthorityConstraint>,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_mint_miss_mint_auth_constraint(
+        _ctx: Context<TestMintMissMintAuthConstraint>,
+        _decimals: u8,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn test_associated_constraint(_ctx: Context<TestAssociatedToken>) -> Result<()> {
+        Ok(())
+    }
 }
 }

+ 554 - 21
tests/misc/tests/misc.ts

@@ -14,7 +14,7 @@ import {
 import { Misc } from "../target/types/misc";
 import { Misc } from "../target/types/misc";
 import { Misc2 } from "../target/types/misc2";
 import { Misc2 } from "../target/types/misc2";
 const utf8 = anchor.utils.bytes.utf8;
 const utf8 = anchor.utils.bytes.utf8;
-const { assert } = require("chai");
+const { assert, expect } = require("chai");
 const nativeAssert = require("assert");
 const nativeAssert = require("assert");
 const miscIdl = require("../target/idl/misc.json");
 const miscIdl = require("../target/idl/misc.json");
 
 
@@ -160,7 +160,7 @@ describe("misc", () => {
       "Program data: jvbowsvlmkcJAAAA",
       "Program data: jvbowsvlmkcJAAAA",
       "Program data: zxM5neEnS1kBAgMEBQYHCAkK",
       "Program data: zxM5neEnS1kBAgMEBQYHCAkK",
       "Program data: g06Ei2GL1gIBAgMEBQYHCAkKCw==",
       "Program data: g06Ei2GL1gIBAgMEBQYHCAkKCw==",
-      "Program 3TEqcc8xhrhdspwbvoamUJe2borm4Nr72JxL66k6rgrh consumed 5395 of 1400000 compute units",
+      "Program 3TEqcc8xhrhdspwbvoamUJe2borm4Nr72JxL66k6rgrh consumed 3983 of 1400000 compute units",
       "Program 3TEqcc8xhrhdspwbvoamUJe2borm4Nr72JxL66k6rgrh success",
       "Program 3TEqcc8xhrhdspwbvoamUJe2borm4Nr72JxL66k6rgrh success",
     ];
     ];
 
 
@@ -232,7 +232,7 @@ describe("misc", () => {
           solDest: data.publicKey,
           solDest: data.publicKey,
         },
         },
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (err) {
     } catch (err) {
       const errMsg = "A close constraint was violated";
       const errMsg = "A close constraint was violated";
       assert.strictEqual(err.error.errorMessage, errMsg);
       assert.strictEqual(err.error.errorMessage, errMsg);
@@ -266,7 +266,7 @@ describe("misc", () => {
     ).lamports;
     ).lamports;
 
 
     // Retrieved rent exemption sol.
     // Retrieved rent exemption sol.
-    assert.ok(afterBalance > beforeBalance);
+    expect(afterBalance > beforeBalance).to.be.true;
 
 
     const closedAccount = await program.provider.connection.getAccountInfo(
     const closedAccount = await program.provider.connection.getAccountInfo(
       data.publicKey
       data.publicKey
@@ -989,7 +989,7 @@ describe("misc", () => {
           owner: anchor.web3.Keypair.generate().publicKey,
           owner: anchor.web3.Keypair.generate().publicKey,
         },
         },
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1028,7 +1028,7 @@ describe("misc", () => {
           owner: anchor.web3.Keypair.generate().publicKey,
           owner: anchor.web3.Keypair.generate().publicKey,
         },
         },
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1057,7 +1057,7 @@ describe("misc", () => {
         },
         },
         signers: [newAcc],
         signers: [newAcc],
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1091,7 +1091,7 @@ describe("misc", () => {
         },
         },
         signers: [mint],
         signers: [mint],
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1125,7 +1125,7 @@ describe("misc", () => {
         },
         },
         signers: [mint],
         signers: [mint],
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1159,7 +1159,7 @@ describe("misc", () => {
         },
         },
         signers: [mint],
         signers: [mint],
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1206,7 +1206,7 @@ describe("misc", () => {
         },
         },
         signers: [token],
         signers: [token],
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1265,7 +1265,7 @@ describe("misc", () => {
         },
         },
         signers: [token],
         signers: [token],
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1318,7 +1318,7 @@ describe("misc", () => {
           authority: anchor.web3.Keypair.generate().publicKey,
           authority: anchor.web3.Keypair.generate().publicKey,
         },
         },
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1383,7 +1383,7 @@ describe("misc", () => {
           authority: program.provider.wallet.publicKey,
           authority: program.provider.wallet.publicKey,
         },
         },
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1449,7 +1449,7 @@ describe("misc", () => {
           authority: program.provider.wallet.publicKey,
           authority: program.provider.wallet.publicKey,
         },
         },
       });
       });
-      assert.ok(false);
+      expect(false).to.be.true;
     } catch (_err) {
     } catch (_err) {
       assert.isTrue(_err instanceof AnchorError);
       assert.isTrue(_err instanceof AnchorError);
       const err: AnchorError = _err;
       const err: AnchorError = _err;
@@ -1463,7 +1463,6 @@ describe("misc", () => {
     await program.rpc.testMultidimensionalArray(array2d, {
     await program.rpc.testMultidimensionalArray(array2d, {
       accounts: {
       accounts: {
         data: data.publicKey,
         data: data.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
       },
       },
       signers: [data],
       signers: [data],
       instructions: [
       instructions: [
@@ -1482,7 +1481,6 @@ describe("misc", () => {
     await program.rpc.testMultidimensionalArrayConstSizes(array2d, {
     await program.rpc.testMultidimensionalArrayConstSizes(array2d, {
       accounts: {
       accounts: {
         data: data.publicKey,
         data: data.publicKey,
-        rent: anchor.web3.SYSVAR_RENT_PUBKEY,
       },
       },
       signers: [data],
       signers: [data],
       instructions: [
       instructions: [
@@ -1520,7 +1518,7 @@ describe("misc", () => {
             second: secondPDA,
             second: secondPDA,
           },
           },
         });
         });
-        assert.ok(false);
+        expect(false).to.be.true;
       } catch (_err) {
       } catch (_err) {
         assert.isTrue(_err instanceof AnchorError);
         assert.isTrue(_err instanceof AnchorError);
         const err: AnchorError = _err;
         const err: AnchorError = _err;
@@ -1535,7 +1533,7 @@ describe("misc", () => {
             second: secondPDA,
             second: secondPDA,
           },
           },
         });
         });
-        assert.ok(false);
+        expect(false).to.be.true;
       } catch (_err) {
       } catch (_err) {
         assert.isTrue(_err instanceof AnchorError);
         assert.isTrue(_err instanceof AnchorError);
         const err: AnchorError = _err;
         const err: AnchorError = _err;
@@ -1574,7 +1572,7 @@ describe("misc", () => {
             second: secondPDA,
             second: secondPDA,
           },
           },
         });
         });
-        assert.ok(false);
+        expect(false).to.be.true;
       } catch (_err) {
       } catch (_err) {
         assert.isTrue(_err instanceof AnchorError);
         assert.isTrue(_err instanceof AnchorError);
         const err: AnchorError = _err;
         const err: AnchorError = _err;
@@ -1589,7 +1587,7 @@ describe("misc", () => {
             second: secondPDA,
             second: secondPDA,
           },
           },
         });
         });
-        assert.ok(false);
+        expect(false).to.be.true;
       } catch (_err) {
       } catch (_err) {
         assert.isTrue(_err instanceof AnchorError);
         assert.isTrue(_err instanceof AnchorError);
         const err: AnchorError = _err;
         const err: AnchorError = _err;
@@ -1605,4 +1603,539 @@ describe("misc", () => {
       });
       });
     });
     });
   });
   });
+  describe("Token Constraint Test", () => {
+    it("Token Constraint Test(no init) - Can make token::mint and token::authority", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      const token = anchor.web3.Keypair.generate();
+      await program.rpc.testInitToken({
+        accounts: {
+          token: token.publicKey,
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [token],
+      });
+      await program.rpc.testTokenConstraint({
+        accounts: {
+          token: token.publicKey,
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+        },
+      });
+      const mintAccount = new Token(
+        program.provider.connection,
+        mint.publicKey,
+        TOKEN_PROGRAM_ID,
+        program.provider.wallet.payer
+      );
+      const account = await mintAccount.getAccountInfo(token.publicKey);
+      assert.isTrue(account.owner.equals(program.provider.wallet.publicKey));
+      assert.isTrue(account.mint.equals(mint.publicKey));
+    });
+
+    it("Token Constraint Test(no init) - Can make only token::authority", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      const token = anchor.web3.Keypair.generate();
+      await program.rpc.testInitToken({
+        accounts: {
+          token: token.publicKey,
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [token],
+      });
+      await program.rpc.testOnlyAuthConstraint({
+        accounts: {
+          token: token.publicKey,
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+        },
+      });
+      const mintAccount = new Token(
+        program.provider.connection,
+        mint.publicKey,
+        TOKEN_PROGRAM_ID,
+        program.provider.wallet.payer
+      );
+      const account = await mintAccount.getAccountInfo(token.publicKey);
+      assert.isTrue(account.owner.equals(program.provider.wallet.publicKey));
+    });
+
+    it("Token Constraint Test(no init) - Can make only token::mint", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      const token = anchor.web3.Keypair.generate();
+      await program.rpc.testInitToken({
+        accounts: {
+          token: token.publicKey,
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [token],
+      });
+      await program.rpc.testOnlyMintConstraint({
+        accounts: {
+          token: token.publicKey,
+          mint: mint.publicKey,
+        },
+      });
+      const mintAccount = new Token(
+        program.provider.connection,
+        mint.publicKey,
+        TOKEN_PROGRAM_ID,
+        program.provider.wallet.payer
+      );
+      const account = await mintAccount.getAccountInfo(token.publicKey);
+      assert.isTrue(account.mint.equals(mint.publicKey));
+    });
+
+    it("Token Constraint Test(no init) - throws if token::mint mismatch", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      const mint1 = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint1.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint1],
+      });
+
+      const token = anchor.web3.Keypair.generate();
+      await program.rpc.testInitToken({
+        accounts: {
+          token: token.publicKey,
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [token],
+      });
+      try {
+        await program.rpc.testTokenConstraint({
+          accounts: {
+            token: token.publicKey,
+            mint: mint1.publicKey,
+            payer: program.provider.wallet.publicKey,
+          },
+        });
+        assert.isTrue(false);
+      } catch (_err) {
+        assert.isTrue(_err instanceof AnchorError);
+        const err: AnchorError = _err;
+        assert.strictEqual(err.error.errorCode.number, 2014);
+        assert.strictEqual(err.error.errorCode.code, "ConstraintTokenMint");
+      }
+    });
+
+    it("Token Constraint Test(no init) - throws if token::authority mismatch", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+      const token = anchor.web3.Keypair.generate();
+      await program.rpc.testInitToken({
+        accounts: {
+          token: token.publicKey,
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [token],
+      });
+      const fakeAuthority = Keypair.generate();
+      try {
+        await program.rpc.testTokenAuthConstraint({
+          accounts: {
+            token: token.publicKey,
+            mint: mint.publicKey,
+            fakeAuthority: fakeAuthority.publicKey,
+          },
+        });
+        assert.isTrue(false);
+      } catch (_err) {
+        assert.isTrue(_err instanceof AnchorError);
+        const err: AnchorError = _err;
+        assert.strictEqual(err.error.errorCode.number, 2015);
+        assert.strictEqual(err.error.errorCode.code, "ConstraintTokenOwner");
+      }
+    });
+
+    it("Token Constraint Test(no init) - throws if both token::authority, token::mint mismatch", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+      const mint1 = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint1.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint1],
+      });
+      const token = anchor.web3.Keypair.generate();
+      await program.rpc.testInitToken({
+        accounts: {
+          token: token.publicKey,
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [token],
+      });
+      const fakeAuthority = Keypair.generate();
+      try {
+        await program.rpc.testTokenAuthConstraint({
+          accounts: {
+            token: token.publicKey,
+            mint: mint1.publicKey,
+            fakeAuthority: fakeAuthority.publicKey,
+          },
+        });
+        assert.isTrue(false);
+      } catch (_err) {
+        assert.isTrue(_err instanceof AnchorError);
+        const err: AnchorError = _err;
+        assert.strictEqual(err.error.errorCode.number, 2015);
+        assert.strictEqual(err.error.errorCode.code, "ConstraintTokenOwner");
+      }
+    });
+
+    it("Mint Constraint Test(no init) - mint::decimals, mint::authority, mint::freeze_authority", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+      await program.rpc.testMintConstraint(6, {
+        accounts: {
+          mint: mint.publicKey,
+          mintAuthority: program.provider.wallet.publicKey,
+          freezeAuthority: program.provider.wallet.publicKey,
+        },
+      });
+      const client = new Token(
+        program.provider.connection,
+        mint.publicKey,
+        TOKEN_PROGRAM_ID,
+        program.provider.wallet.payer
+      );
+      const mintAccount = await client.getMintInfo();
+      assert.strictEqual(mintAccount.decimals, 6);
+      assert.isTrue(
+        mintAccount.mintAuthority.equals(program.provider.wallet.publicKey)
+      );
+      assert.isTrue(
+        mintAccount.freezeAuthority.equals(program.provider.wallet.publicKey)
+      );
+    });
+
+    it("Mint Constraint Test(no init) - throws if mint::decimals mismatch", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+      const fakeDecimal = 5;
+      try {
+        await program.rpc.testMintConstraint(fakeDecimal, {
+          accounts: {
+            mint: mint.publicKey,
+            mintAuthority: program.provider.wallet.publicKey,
+            freezeAuthority: program.provider.wallet.publicKey,
+          },
+        });
+        assert.isTrue(false);
+      } catch (_err) {
+        assert.isTrue(_err instanceof AnchorError);
+        const err: AnchorError = _err;
+        assert.strictEqual(err.error.errorCode.number, 2018);
+        assert.strictEqual(err.error.errorCode.code, "ConstraintMintDecimals");
+      }
+    });
+
+    it("Mint Constraint Test(no init) - throws if mint::mint_authority mismatch", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      const fakeAuthority = Keypair.generate();
+      try {
+        await program.rpc.testMintConstraint(6, {
+          accounts: {
+            mint: mint.publicKey,
+            mintAuthority: fakeAuthority.publicKey,
+            freezeAuthority: program.provider.wallet.publicKey,
+          },
+        });
+        assert.isTrue(false);
+      } catch (_err) {
+        assert.isTrue(_err instanceof AnchorError);
+        const err: AnchorError = _err;
+        assert.strictEqual(err.error.errorCode.number, 2016);
+        assert.strictEqual(
+          err.error.errorCode.code,
+          "ConstraintMintMintAuthority"
+        );
+      }
+    });
+
+    it("Mint Constraint Test(no init) - throws if mint::freeze_authority mismatch", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      const fakeAuthority = Keypair.generate();
+      try {
+        await program.rpc.testMintConstraint(6, {
+          accounts: {
+            mint: mint.publicKey,
+            mintAuthority: program.provider.wallet.publicKey,
+            freezeAuthority: fakeAuthority.publicKey,
+          },
+        });
+        assert.isTrue(false);
+      } catch (_err) {
+        assert.isTrue(_err instanceof AnchorError);
+        const err: AnchorError = _err;
+        assert.strictEqual(err.error.errorCode.number, 2017);
+        assert.strictEqual(
+          err.error.errorCode.code,
+          "ConstraintMintFreezeAuthority"
+        );
+      }
+    });
+
+    it("Mint Constraint Test(no init) - can write only mint::decimals", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      await program.rpc.testMintOnlyDecimalsConstraint(6, {
+        accounts: {
+          mint: mint.publicKey,
+        },
+      });
+      const client = new Token(
+        program.provider.connection,
+        mint.publicKey,
+        TOKEN_PROGRAM_ID,
+        program.provider.wallet.payer
+      );
+      const mintAccount = await client.getMintInfo();
+      assert.strictEqual(mintAccount.decimals, 6);
+    });
+
+    it("Mint Constraint Test(no init) - can write only mint::authority and mint::freeze_authority", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      await program.rpc.testMintOnlyAuthConstraint({
+        accounts: {
+          mint: mint.publicKey,
+          mintAuthority: program.provider.wallet.publicKey,
+          freezeAuthority: program.provider.wallet.publicKey,
+        },
+      });
+      const client = new Token(
+        program.provider.connection,
+        mint.publicKey,
+        TOKEN_PROGRAM_ID,
+        program.provider.wallet.payer
+      );
+      const mintAccount = await client.getMintInfo();
+      assert.isTrue(
+        mintAccount.mintAuthority.equals(program.provider.wallet.publicKey)
+      );
+      assert.isTrue(
+        mintAccount.freezeAuthority.equals(program.provider.wallet.publicKey)
+      );
+    });
+
+    it("Mint Constraint Test(no init) - can write only mint::authority", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      await program.rpc.testMintOnlyOneAuthConstraint({
+        accounts: {
+          mint: mint.publicKey,
+          mintAuthority: program.provider.wallet.publicKey,
+        },
+      });
+      const client = new Token(
+        program.provider.connection,
+        mint.publicKey,
+        TOKEN_PROGRAM_ID,
+        program.provider.wallet.payer
+      );
+      const mintAccount = await client.getMintInfo();
+      assert.isTrue(
+        mintAccount.mintAuthority.equals(program.provider.wallet.publicKey)
+      );
+    });
+
+    it("Mint Constraint Test(no init) - can write only mint::decimals and mint::freeze_authority", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.rpc.testInitMint({
+        accounts: {
+          mint: mint.publicKey,
+          payer: program.provider.wallet.publicKey,
+          systemProgram: anchor.web3.SystemProgram.programId,
+          tokenProgram: TOKEN_PROGRAM_ID,
+          rent: anchor.web3.SYSVAR_RENT_PUBKEY,
+        },
+        signers: [mint],
+      });
+
+      await program.rpc.testMintMissMintAuthConstraint(6, {
+        accounts: {
+          mint: mint.publicKey,
+          freezeAuthority: program.provider.wallet.publicKey,
+        },
+      });
+      const client = new Token(
+        program.provider.connection,
+        mint.publicKey,
+        TOKEN_PROGRAM_ID,
+        program.provider.wallet.payer
+      );
+      const mintAccount = await client.getMintInfo();
+      assert.strictEqual(mintAccount.decimals, 6);
+      assert.isTrue(
+        mintAccount.freezeAuthority.equals(program.provider.wallet.publicKey)
+      );
+    });
+  });
 });
 });