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

This commit is contained in:
Alan O'Donnell 2021-10-05 11:36:17 -07:00 committed by GitHub
parent 8566b909cf
commit dbb5f48b24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 9 deletions

View File

@ -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)). * 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)). * 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 ## [0.17.0] - 2021-10-03

View File

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

View File

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

View File

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

View File

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

View File

@ -455,6 +455,9 @@ describe("misc", () => {
assert.ok( assert.ok(
mintAccount.mintAuthority.equals(program.provider.wallet.publicKey) 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 () => { it("Can create a random mint account prefunded", async () => {