Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add interest bearing mint extension #3278

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
24 changes: 24 additions & 0 deletions lang/syn/src/codegen/accounts/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -688,6 +688,8 @@ fn generate_constraint_init_group(
metadata_pointer_metadata_address,
close_authority,
permanent_delegate,
interest_bearing_mint_rate,
interest_bearing_mint_authority,
transfer_hook_authority,
transfer_hook_program_id,
} => {
Expand Down Expand Up @@ -805,6 +807,10 @@ fn generate_constraint_init_group(
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::PermanentDelegate});
}

if interest_bearing_mint_rate.is_some() {
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::InterestBearingConfig});
}

let mint_space = if extensions.is_empty() {
quote! { ::anchor_spl::token::Mint::LEN }
} else {
Expand Down Expand Up @@ -864,6 +870,18 @@ fn generate_constraint_init_group(
None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None },
};

let interest_bearing_mint_rate = match interest_bearing_mint_rate {
Some(ibmr) => quote! { Option::<i16>::Some(#ibmr) },
None => quote! { Option::<i16>::None },
};

let interest_bearing_mint_authority = match interest_bearing_mint_authority {
Some(ibma) => {
quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#ibma.key()) }
}
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
};

let transfer_hook_authority = match transfer_hook_authority {
Some(tha) => quote! { Option::<anchor_lang::prelude::Pubkey>::Some(#tha.key()) },
None => quote! { Option::<anchor_lang::prelude::Pubkey>::None },
Expand Down Expand Up @@ -946,6 +964,12 @@ fn generate_constraint_init_group(
mint: #field.to_account_info(),
}), #permanent_delegate.unwrap())?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::InterestBearingConfig => {
::anchor_spl::token_interface::interest_bearing_mint_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::InterestBearingMintInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
}), #interest_bearing_mint_authority, #interest_bearing_mint_rate.unwrap())?;
},
// All extensions specified by the user should be implemented.
// If this line runs, it means there is a bug in the codegen.
_ => unimplemented!("{e:?}"),
Expand Down
14 changes: 14 additions & 0 deletions lang/syn/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,8 @@ pub enum ConstraintToken {
ExtensionTokenHookAuthority(Context<ConstraintExtensionAuthority>),
ExtensionTokenHookProgramId(Context<ConstraintExtensionTokenHookProgramId>),
ExtensionPermanentDelegate(Context<ConstraintExtensionPermanentDelegate>),
ExtensionInterestBearingMintRate(Context<ConstraintExtensionInterestBearingMintRate>),
ExtensionInterestBearingMintAuthority(Context<ConstraintExtensionAuthority>),
}

impl Parse for ConstraintToken {
Expand Down Expand Up @@ -905,6 +907,11 @@ pub struct ConstraintExtensionAuthority {
pub authority: Expr,
}

#[derive(Debug, Clone)]
pub struct ConstraintBool {
pub enable: Expr,
}

#[derive(Debug, Clone)]
pub struct ConstraintExtensionGroupPointerGroupAddress {
pub group_address: Expr,
Expand All @@ -930,6 +937,11 @@ pub struct ConstraintExtensionPermanentDelegate {
pub permanent_delegate: Expr,
}

#[derive(Debug, Clone)]
pub struct ConstraintExtensionInterestBearingMintRate {
pub rate: Expr,
}

#[derive(Debug, Clone)]
#[allow(clippy::large_enum_variant)]
pub enum InitKind {
Expand Down Expand Up @@ -965,6 +977,8 @@ pub enum InitKind {
metadata_pointer_metadata_address: Option<Expr>,
close_authority: Option<Expr>,
permanent_delegate: Option<Expr>,
interest_bearing_mint_rate: Option<Expr>,
interest_bearing_mint_authority: Option<Expr>,
transfer_hook_authority: Option<Expr>,
transfer_hook_program_id: Option<Expr>,
},
Expand Down
74 changes: 74 additions & 0 deletions lang/syn/src/parser/accounts/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,35 @@ pub fn parse_token(stream: ParseStream) -> ParseResult<ConstraintToken> {
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
"interest_bearing_mint" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
let kw = stream.call(Ident::parse_any)?.to_string();
stream.parse::<Token![=]>()?;

let span = ident
.span()
.join(stream.span())
.unwrap_or_else(|| ident.span());

match kw.as_str() {
"rate" => ConstraintToken::ExtensionInterestBearingMintRate(Context::new(
span,
ConstraintExtensionInterestBearingMintRate {
rate: stream.parse()?,
},
)),
"authority" => {
ConstraintToken::ExtensionInterestBearingMintAuthority(Context::new(
span,
ConstraintExtensionAuthority {
authority: stream.parse()?,
},
))
}
_ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
}
}
"transfer_hook" => {
stream.parse::<Token![:]>()?;
stream.parse::<Token![:]>()?;
Expand Down Expand Up @@ -525,6 +554,7 @@ pub struct ConstraintGroupBuilder<'ty> {
pub mint_freeze_authority: Option<Context<ConstraintMintFreezeAuthority>>,
pub mint_decimals: Option<Context<ConstraintMintDecimals>>,
pub mint_token_program: Option<Context<ConstraintTokenProgram>>,
// mint extensions.
pub extension_group_pointer_authority: Option<Context<ConstraintExtensionAuthority>>,
pub extension_group_pointer_group_address:
Option<Context<ConstraintExtensionGroupPointerGroupAddress>>,
Expand All @@ -538,6 +568,9 @@ pub struct ConstraintGroupBuilder<'ty> {
pub extension_transfer_hook_authority: Option<Context<ConstraintExtensionAuthority>>,
pub extension_transfer_hook_program_id: Option<Context<ConstraintExtensionTokenHookProgramId>>,
pub extension_permanent_delegate: Option<Context<ConstraintExtensionPermanentDelegate>>,
pub extension_interest_bearing_mint_rate:
Option<Context<ConstraintExtensionInterestBearingMintRate>>,
pub extension_interest_bearing_mint_authority: Option<Context<ConstraintExtensionAuthority>>,
pub bump: Option<Context<ConstraintTokenBump>>,
pub program_seed: Option<Context<ConstraintProgramSeed>>,
pub realloc: Option<Context<ConstraintRealloc>>,
Expand Down Expand Up @@ -583,6 +616,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
extension_transfer_hook_authority: None,
extension_transfer_hook_program_id: None,
extension_permanent_delegate: None,
extension_interest_bearing_mint_rate: None,
extension_interest_bearing_mint_authority: None,
bump: None,
program_seed: None,
realloc: None,
Expand Down Expand Up @@ -795,6 +830,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
extension_transfer_hook_authority,
extension_transfer_hook_program_id,
extension_permanent_delegate,
extension_interest_bearing_mint_rate,
extension_interest_bearing_mint_authority,
bump,
program_seed,
realloc,
Expand Down Expand Up @@ -975,6 +1012,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
)),
},
token_program: token_token_program.map(|tp| tp.into_inner().token_program),

}
} else if let Some(at) = &associated_token {
InitKind::AssociatedToken {
Expand Down Expand Up @@ -1003,6 +1041,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
metadata_pointer_metadata_address: extension_metadata_pointer_metadata_address.map(|mpma| mpma.into_inner().metadata_address),
close_authority: extension_close_authority.map(|ca| ca.into_inner().authority),
permanent_delegate: extension_permanent_delegate.map(|pd| pd.into_inner().permanent_delegate),
interest_bearing_mint_rate: extension_interest_bearing_mint_rate.map(|ibmr| ibmr.into_inner().rate),
interest_bearing_mint_authority: extension_interest_bearing_mint_authority.map(|ibma| ibma.into_inner().authority),
transfer_hook_authority: extension_transfer_hook_authority.map(|tha| tha.into_inner().authority),
transfer_hook_program_id: extension_transfer_hook_program_id.map(|thpid| thpid.into_inner().program_id),
}
Expand Down Expand Up @@ -1093,6 +1133,12 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
ConstraintToken::ExtensionPermanentDelegate(c) => {
self.add_extension_permanent_delegate(c)
}
ConstraintToken::ExtensionInterestBearingMintRate(c) => {
self.add_extension_interest_bearing_mint_rate(c)
}
ConstraintToken::ExtensionInterestBearingMintAuthority(c) => {
self.add_extension_interest_bearing_mint_authority(c)
}
}
}

Expand Down Expand Up @@ -1675,4 +1721,32 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
self.extension_permanent_delegate.replace(c);
Ok(())
}

fn add_extension_interest_bearing_mint_rate(
&mut self,
c: Context<ConstraintExtensionInterestBearingMintRate>,
) -> ParseResult<()> {
if self.extension_interest_bearing_mint_rate.is_some() {
return Err(ParseError::new(
c.span(),
"extension interest bearing mint rate already provided",
));
}
self.extension_interest_bearing_mint_rate.replace(c);
Ok(())
}

fn add_extension_interest_bearing_mint_authority(
&mut self,
c: Context<ConstraintExtensionAuthority>,
) -> ParseResult<()> {
if self.extension_interest_bearing_mint_authority.is_some() {
return Err(ParseError::new(
c.span(),
"extension interest bearing mint rate authority already provided",
));
}
self.extension_interest_bearing_mint_authority.replace(c);
Ok(())
}
}
Loading