Bläddra i källkod

lang: Add mint::freeze_authority attribute for init mint (#835)

Alan O'Donnell 4 år sedan
förälder
incheckning
dbb5f48b24

+ 1 - 0
CHANGELOG.md

@@ -15,6 +15,7 @@ incremented for features.
 
 * cli: `target/types` directory now created on build to store a TypeScript types file for each program's IDL ([#795](https://github.com/project-serum/anchor/pull/795)).
 * ts: `Program<T>` can now be typed with an IDL type ([#795](https://github.com/project-serum/anchor/pull/795)).
+* lang: Add `mint::freeze_authority` keyword for mint initialization within `#[derive(Accounts)]` ([#835](https://github.com/project-serum/anchor/pull/835)).
 
 ## [0.17.0] - 2021-10-03
 

+ 10 - 2
lang/syn/src/codegen/accounts/constraints.rs

@@ -433,13 +433,21 @@ pub fn generate_init(
                 };
             }
         }
-        InitKind::Mint { owner, decimals } => {
+        InitKind::Mint {
+            owner,
+            decimals,
+            freeze_authority,
+        } => {
             let create_account = generate_create_account(
                 field,
                 quote! {anchor_spl::token::Mint::LEN},
                 quote! {token_program.to_account_info().key},
                 seeds_with_nonce,
             );
+            let freeze_authority = match freeze_authority {
+                Some(fa) => quote! { Some(&#fa.key()) },
+                None => quote! { None },
+            };
             quote! {
                 let #field: #ty_decl = {
                     // Define payer variable.
@@ -455,7 +463,7 @@ pub fn generate_init(
                         rent: rent.to_account_info(),
                     };
                     let cpi_ctx = CpiContext::new(cpi_program, accounts);
-                    anchor_spl::token::initialize_mint(cpi_ctx, #decimals, &#owner.to_account_info().key, None)?;
+                    anchor_spl::token::initialize_mint(cpi_ctx, #decimals, &#owner.to_account_info().key, #freeze_authority)?;
                     let pa: #ty_decl = #from_account_info;
                     pa
                 };

+ 22 - 4
lang/syn/src/lib.rs

@@ -564,6 +564,7 @@ pub enum ConstraintToken {
     AssociatedTokenMint(Context<ConstraintTokenMint>),
     AssociatedTokenAuthority(Context<ConstraintTokenAuthority>),
     MintAuthority(Context<ConstraintMintAuthority>),
+    MintFreezeAuthority(Context<ConstraintMintFreezeAuthority>),
     MintDecimals(Context<ConstraintMintDecimals>),
     Bump(Context<ConstraintTokenBump>),
 }
@@ -658,12 +659,24 @@ pub struct ConstraintSpace {
 #[derive(Debug, Clone)]
 #[allow(clippy::large_enum_variant)]
 pub enum InitKind {
-    Program { owner: Option<Expr> },
+    Program {
+        owner: Option<Expr>,
+    },
     // Owner for token and mint represents the authority. Not to be confused
     // with the owner of the AccountInfo.
-    Token { owner: Expr, mint: Expr },
-    AssociatedToken { owner: Expr, mint: Expr },
-    Mint { owner: Expr, decimals: Expr },
+    Token {
+        owner: Expr,
+        mint: Expr,
+    },
+    AssociatedToken {
+        owner: Expr,
+        mint: Expr,
+    },
+    Mint {
+        owner: Expr,
+        freeze_authority: Option<Expr>,
+        decimals: Expr,
+    },
 }
 
 #[derive(Debug, Clone)]
@@ -686,6 +699,11 @@ pub struct ConstraintMintAuthority {
     mint_auth: Expr,
 }
 
+#[derive(Debug, Clone)]
+pub struct ConstraintMintFreezeAuthority {
+    mint_freeze_auth: Expr,
+}
+
 #[derive(Debug, Clone)]
 pub struct ConstraintMintDecimals {
     decimals: Expr,

+ 32 - 1
lang/syn/src/parser/accounts/constraints.rs

@@ -85,6 +85,12 @@ pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
                         mint_auth: stream.parse()?,
                     },
                 )),
+                "freeze_authority" => ConstraintToken::MintFreezeAuthority(Context::new(
+                    span,
+                    ConstraintMintFreezeAuthority {
+                        mint_freeze_auth: stream.parse()?,
+                    },
+                )),
                 "decimals" => ConstraintToken::MintDecimals(Context::new(
                     span,
                     ConstraintMintDecimals {
@@ -276,6 +282,7 @@ pub struct ConstraintGroupBuilder<'ty> {
     pub associated_token_mint: Option<Context<ConstraintTokenMint>>,
     pub associated_token_authority: Option<Context<ConstraintTokenAuthority>>,
     pub mint_authority: Option<Context<ConstraintMintAuthority>>,
+    pub mint_freeze_authority: Option<Context<ConstraintMintFreezeAuthority>>,
     pub mint_decimals: Option<Context<ConstraintMintDecimals>>,
     pub bump: Option<Context<ConstraintTokenBump>>,
 }
@@ -305,6 +312,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             associated_token_mint: None,
             associated_token_authority: None,
             mint_authority: None,
+            mint_freeze_authority: None,
             mint_decimals: None,
             bump: None,
         }
@@ -460,6 +468,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             associated_token_mint,
             associated_token_authority,
             mint_authority,
+            mint_freeze_authority,
             mint_decimals,
             bump,
         } = self;
@@ -523,7 +532,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
                                 d.span(),
                                 "authority must be provided to initialize a mint program derived address"
                             ))
-                        }
+                        },
+                        freeze_authority: mint_freeze_authority.map(|fa| fa.into_inner().mint_freeze_auth)
                     }
                 } else {
                     InitKind::Program {
@@ -570,6 +580,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             ConstraintToken::AssociatedTokenAuthority(c) => self.add_associated_token_authority(c),
             ConstraintToken::AssociatedTokenMint(c) => self.add_associated_token_mint(c),
             ConstraintToken::MintAuthority(c) => self.add_mint_authority(c),
+            ConstraintToken::MintFreezeAuthority(c) => self.add_mint_freeze_authority(c),
             ConstraintToken::MintDecimals(c) => self.add_mint_decimals(c),
             ConstraintToken::Bump(c) => self.add_bump(c),
         }
@@ -739,6 +750,26 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
         Ok(())
     }
 
+    fn add_mint_freeze_authority(
+        &mut self,
+        c: Context<ConstraintMintFreezeAuthority>,
+    ) -> ParseResult<()> {
+        if self.mint_freeze_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "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);
+        Ok(())
+    }
+
     fn add_mint_decimals(&mut self, c: Context<ConstraintMintDecimals>) -> ParseResult<()> {
         if self.mint_decimals.is_some() {
             return Err(ParseError::new(c.span(), "mint decimals already provided"));

+ 2 - 2
tests/misc/programs/misc/src/context.rs

@@ -183,7 +183,7 @@ pub struct TestInitZeroCopy<'info> {
 
 #[derive(Accounts)]
 pub struct TestInitMint<'info> {
-    #[account(init, mint::decimals = 6, mint::authority = payer, payer = payer)]
+    #[account(init, mint::decimals = 6, mint::authority = payer, mint::freeze_authority = payer, payer = payer)]
     pub mint: Account<'info, Mint>,
     #[account(signer)]
     pub payer: AccountInfo<'info>,
@@ -218,4 +218,4 @@ pub struct TestFetchAll<'info> {
     pub data: Account<'info, DataWithFilter>,
     pub authority: Signer<'info>,
     pub system_program: Program<'info, System>,
-}
+}

+ 3 - 0
tests/misc/tests/misc.js

@@ -455,6 +455,9 @@ describe("misc", () => {
     assert.ok(
       mintAccount.mintAuthority.equals(program.provider.wallet.publicKey)
     );
+    assert.ok(
+      mintAccount.freezeAuthority.equals(program.provider.wallet.publicKey)
+    );
   });
 
   it("Can create a random mint account prefunded", async () => {