From 3846f3ac411bc0a4f0831959e506b0b29dace684 Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Sat, 27 Jul 2024 15:37:08 -0400 Subject: [PATCH 01/13] add interest bearing mint rate extension --- lang/syn/src/codegen/accounts/constraints.rs | 18 +++++ lang/syn/src/lib.rs | 9 +++ lang/syn/src/parser/accounts/constraints.rs | 69 ++++++++++++++++++++ 3 files changed, 96 insertions(+) diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 1683d582fe..8a36be4a34 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -681,6 +681,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, } => { @@ -857,6 +859,16 @@ 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::<&anchor_lang::prelude::Pubkey>::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::::Some(#tha.key()) }, None => quote! { Option::::None }, @@ -939,6 +951,12 @@ fn generate_constraint_init_group( mint: #field.to_account_info(), }), #permanent_delegate.unwrap())?; }, + ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::InterestBearingMint => { + ::anchor_spl::token_interface::interest_bearing_mint(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::InterestBearingMints { + token_program_id: #token_program.to_account_info(), + mint: #field.to_account_info(), + }), #interest_bearing_mint_authority.unwrap(), #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:?}"), diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index ad4a18399d..4a4840da33 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -695,6 +695,8 @@ pub enum ConstraintToken { ExtensionTokenHookAuthority(Context), ExtensionTokenHookProgramId(Context), ExtensionPermanentDelegate(Context), + ExtensionInterestBearingMintRate(Context), + ExtensionInterestBearingMintAuthority(Context), } impl Parse for ConstraintToken { @@ -842,6 +844,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 { @@ -877,6 +884,8 @@ pub enum InitKind { metadata_pointer_metadata_address: Option, close_authority: Option, permanent_delegate: Option, + interest_bearing_mint_rate: Option, + interest_bearing_mint_authority: Option, transfer_hook_authority: Option, transfer_hook_program_id: Option, }, diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index 89fe224464..4b330d4761 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -230,6 +230,33 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { _ => return Err(ParseError::new(ident.span(), "Invalid attribute")), } } + "interest_bearing_mint" => { + stream.parse::()?; + stream.parse::()?; + let kw = stream.call(Ident::parse_any)?.to_string(); + stream.parse::()?; + + 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::()?; stream.parse::()?; @@ -538,6 +565,8 @@ pub struct ConstraintGroupBuilder<'ty> { pub extension_transfer_hook_authority: Option>, pub extension_transfer_hook_program_id: Option>, pub extension_permanent_delegate: Option>, + pub extension_interest_bearing_mint_rate: Option>, + pub extension_interest_bearing_mint_authority: Option>, pub bump: Option>, pub program_seed: Option>, pub realloc: Option>, @@ -583,6 +612,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, @@ -795,6 +826,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, @@ -1003,6 +1036,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), } @@ -1093,6 +1128,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) + } } } @@ -1670,4 +1711,32 @@ impl<'ty> ConstraintGroupBuilder<'ty> { self.extension_permanent_delegate.replace(c); Ok(()) } + + fn add_extension_interest_bearing_mint_rate( + &mut self, + c: Context, + ) -> 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, + ) -> 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(()) + } } From d25220f4bd9455cc0d5796c3c1c403319672198f Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Sat, 27 Jul 2024 15:37:18 -0400 Subject: [PATCH 02/13] fmt --- lang/syn/src/codegen/accounts/constraints.rs | 4 +++- lang/syn/src/parser/accounts/constraints.rs | 17 ++++++++++------- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 8a36be4a34..294682f9aa 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -865,7 +865,9 @@ fn generate_constraint_init_group( }; let interest_bearing_mint_authority = match interest_bearing_mint_authority { - Some(ibma) => quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#ibma.key()) }, + Some(ibma) => { + quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#ibma.key()) } + } None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None }, }; diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index 4b330d4761..29087cfc1e 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -248,12 +248,14 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { rate: stream.parse()?, }, )), - "authority" => ConstraintToken::ExtensionInterestBearingMintAuthority(Context::new( - span, - ConstraintExtensionAuthority { - authority: stream.parse()?, - }, - )), + "authority" => { + ConstraintToken::ExtensionInterestBearingMintAuthority(Context::new( + span, + ConstraintExtensionAuthority { + authority: stream.parse()?, + }, + )) + } _ => return Err(ParseError::new(ident.span(), "Invalid attribute")), } } @@ -565,7 +567,8 @@ pub struct ConstraintGroupBuilder<'ty> { pub extension_transfer_hook_authority: Option>, pub extension_transfer_hook_program_id: Option>, pub extension_permanent_delegate: Option>, - pub extension_interest_bearing_mint_rate: Option>, + pub extension_interest_bearing_mint_rate: + Option>, pub extension_interest_bearing_mint_authority: Option>, pub bump: Option>, pub program_seed: Option>, From 51cb5492fef1490b102d2400b1e6138bad17c2ed Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Sat, 27 Jul 2024 15:47:26 -0400 Subject: [PATCH 03/13] update interest mint --- lang/syn/src/codegen/accounts/constraints.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 294682f9aa..e1369b2b87 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -953,8 +953,8 @@ fn generate_constraint_init_group( mint: #field.to_account_info(), }), #permanent_delegate.unwrap())?; }, - ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::InterestBearingMint => { - ::anchor_spl::token_interface::interest_bearing_mint(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::InterestBearingMints { + ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::InterestBearingConfig => { + ::anchor_spl::token_interface::interest_bearing_mint(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::InterestBearingMint { token_program_id: #token_program.to_account_info(), mint: #field.to_account_info(), }), #interest_bearing_mint_authority.unwrap(), #interest_bearing_mint_rate.unwrap())?; From 94fd3f8a67c393e7e702bb3d197564064a27408b Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Sat, 27 Jul 2024 15:58:40 -0400 Subject: [PATCH 04/13] fix interest bearing mint initialize --- lang/syn/src/codegen/accounts/constraints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index e1369b2b87..ea2a16f39b 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -954,7 +954,7 @@ fn generate_constraint_init_group( }), #permanent_delegate.unwrap())?; }, ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::InterestBearingConfig => { - ::anchor_spl::token_interface::interest_bearing_mint(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::InterestBearingMint { + ::anchor_spl::token_interface::interest_bearing_mint(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.unwrap(), #interest_bearing_mint_rate.unwrap())?; From d74e6d27d79866bad425e197a378fb58d39d7b48 Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Sat, 27 Jul 2024 16:00:49 -0400 Subject: [PATCH 05/13] fix funciton call --- lang/syn/src/codegen/accounts/constraints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index ea2a16f39b..31f77b8ff3 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -954,7 +954,7 @@ fn generate_constraint_init_group( }), #permanent_delegate.unwrap())?; }, ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::InterestBearingConfig => { - ::anchor_spl::token_interface::interest_bearing_mint(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::InterestBearingMintInitialize { + ::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.unwrap(), #interest_bearing_mint_rate.unwrap())?; From d38b143cf4fb19d489fac5dc54ad94ba101af060 Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Sat, 27 Jul 2024 16:04:54 -0400 Subject: [PATCH 06/13] fix function args --- lang/syn/src/codegen/accounts/constraints.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 31f77b8ff3..919c0173bf 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -860,15 +860,15 @@ fn generate_constraint_init_group( }; let interest_bearing_mint_rate = match interest_bearing_mint_rate { - Some(ibmr) => quote! { Option::<&i16>::Some(&#ibmr) }, - None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None }, + Some(ibmr) => quote! { Option::::Some(#ibmr) }, + None => quote! { Option::::None }, }; let interest_bearing_mint_authority = match interest_bearing_mint_authority { Some(ibma) => { - quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#ibma.key()) } + quote! { Option::::Some(#ibma.key()) } } - None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None }, + None => quote! { Option::::None }, }; let transfer_hook_authority = match transfer_hook_authority { @@ -957,7 +957,7 @@ fn generate_constraint_init_group( ::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.unwrap(), #interest_bearing_mint_rate.unwrap())?; + }), #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. From c138b4d2c6263474a42aba4057c8d9a9c9c8daf5 Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Sat, 27 Jul 2024 16:50:43 -0400 Subject: [PATCH 07/13] actually init --- lang/syn/src/codegen/accounts/constraints.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 919c0173bf..1e893bbf51 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -800,6 +800,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 { From db56cf24a830cf28c106cd37f89897b979848b4d Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Mon, 29 Jul 2024 10:08:49 -0400 Subject: [PATCH 08/13] add memo transfer --- lang/syn/src/codegen/accounts/constraints.rs | 35 ++++++++++++++++++++ lang/syn/src/lib.rs | 7 ++++ lang/syn/src/parser/accounts/constraints.rs | 25 ++++++++++++++ 3 files changed, 67 insertions(+) diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index 1e893bbf51..4337d407a5 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -518,6 +518,7 @@ fn generate_constraint_init_group( owner, mint, token_program, + memo_transfer, } => { let token_program = match token_program { Some(t) => t.to_token_stream(), @@ -531,12 +532,31 @@ fn generate_constraint_init_group( let token_program_optional_check = check_scope.generate_check(&token_program); let rent_optional_check = check_scope.generate_check(rent); + // extension checks + let memo_transfer_check = match memo_transfer { + Some(gpa) => check_scope.generate_check(gpa), + None => quote! {}, + }; + let optional_checks = quote! { #system_program_optional_check #token_program_optional_check #rent_optional_check #owner_optional_check #mint_optional_check + #memo_transfer_check + }; + + let mut extensions = vec![]; + + if memo_transfer.is_some() { + extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MemoTransfer}); + } + + let extensions = if extensions.is_empty() { + quote! {Option::<&::anchor_spl::token_interface::ExtensionsVec>::None} + } else { + quote! {Option::<&::anchor_spl::token_interface::ExtensionsVec>::Some(&vec![#(#extensions),*])} }; let payer_optional_check = check_scope.generate_check(payer); @@ -566,6 +586,21 @@ fn generate_constraint_init_group( // Create the account with the system program. #create_account + if let Some(extensions) = #extensions { + for e in extensions { + match e { + ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MemoTransfer => { + ::anchor_spl::token_interface::memo_transfer_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::MemoTransfer { + token_program_id: #token_program.to_account_info(), + account: #field.to_account_info(), + owner: #owner.to_account_info(), + }))?; + }, + + } + } + } + // Initialize the token account. let cpi_program = #token_program.to_account_info(); let accounts = ::anchor_spl::token_interface::InitializeAccount3 { diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index 4a4840da33..6782b2db1e 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -668,6 +668,7 @@ pub enum ConstraintToken { TokenMint(Context), TokenAuthority(Context), TokenTokenProgram(Context), + ExtensionTransferMemo(Context), AssociatedTokenMint(Context), AssociatedTokenAuthority(Context), AssociatedTokenTokenProgram(Context), @@ -819,6 +820,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, @@ -864,6 +870,7 @@ pub enum InitKind { owner: Expr, mint: Expr, token_program: Option, + memo_transfer: Option, }, AssociatedToken { owner: Expr, diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index 29087cfc1e..fa64f5c0c6 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -319,6 +319,12 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { token_program: stream.parse()?, }, )), + "transfer_memp" => ConstraintToken::ExtensionTransferMemo(Context::new( + span, + ConstraintBool { + enable: stream.parse()?, + }, + )), _ => return Err(ParseError::new(ident.span(), "Invalid attribute")), } } @@ -554,6 +560,7 @@ pub struct ConstraintGroupBuilder<'ty> { pub mint_freeze_authority: Option>, pub mint_decimals: Option>, pub mint_token_program: Option>, + // mint extensions. pub extension_group_pointer_authority: Option>, pub extension_group_pointer_group_address: Option>, @@ -570,6 +577,8 @@ pub struct ConstraintGroupBuilder<'ty> { pub extension_interest_bearing_mint_rate: Option>, pub extension_interest_bearing_mint_authority: Option>, + // token extensions. + pub extension_memo_transfer: Option>, pub bump: Option>, pub program_seed: Option>, pub realloc: Option>, @@ -598,6 +607,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> { token_mint: None, token_authority: None, token_token_program: None, + extension_memo_transfer: None, associated_token_mint: None, associated_token_authority: None, associated_token_token_program: None, @@ -831,6 +841,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> { extension_permanent_delegate, extension_interest_bearing_mint_rate, extension_interest_bearing_mint_authority, + extension_memo_transfer, bump, program_seed, realloc, @@ -1011,6 +1022,8 @@ impl<'ty> ConstraintGroupBuilder<'ty> { )), }, token_program: token_token_program.map(|tp| tp.into_inner().token_program), + memo_transfer: extension_memo_transfer.map(|mt| mt.into_inner().enable), + } } else if let Some(at) = &associated_token { InitKind::AssociatedToken { @@ -1091,6 +1104,7 @@ impl<'ty> ConstraintGroupBuilder<'ty> { ConstraintToken::TokenAuthority(c) => self.add_token_authority(c), ConstraintToken::TokenMint(c) => self.add_token_mint(c), ConstraintToken::TokenTokenProgram(c) => self.add_token_token_program(c), + ConstraintToken::ExtensionTransferMemo(c) => self.add_extension_memo_transfer(c), ConstraintToken::AssociatedTokenAuthority(c) => self.add_associated_token_authority(c), ConstraintToken::AssociatedTokenMint(c) => self.add_associated_token_mint(c), ConstraintToken::AssociatedTokenTokenProgram(c) => { @@ -1422,6 +1436,17 @@ impl<'ty> ConstraintGroupBuilder<'ty> { Ok(()) } + fn add_extension_memo_transfer(&mut self, c: Context) -> ParseResult<()> { + if self.extension_memo_transfer.is_some() { + return Err(ParseError::new( + c.span(), + "extension memo transfer already provided", + )); + } + self.extension_memo_transfer.replace(c); + Ok(()) + } + fn add_associated_token_token_program( &mut self, c: Context, From c46c1bf1b12163d5d00ed9edd7e72e1a117362bb Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Mon, 29 Jul 2024 10:12:19 -0400 Subject: [PATCH 09/13] fix naming --- lang/syn/src/parser/accounts/constraints.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index fa64f5c0c6..dfe5d71c36 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -319,7 +319,7 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { token_program: stream.parse()?, }, )), - "transfer_memp" => ConstraintToken::ExtensionTransferMemo(Context::new( + "transfer_memo" => ConstraintToken::ExtensionTransferMemo(Context::new( span, ConstraintBool { enable: stream.parse()?, From 1f5698aed552f0f3d1014efe91593541f290d56f Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Wed, 25 Sep 2024 17:25:18 -0400 Subject: [PATCH 10/13] remove transfer memo --- lang/syn/src/codegen/accounts/constraints.rs | 35 -------------------- lang/syn/src/lib.rs | 2 -- lang/syn/src/parser/accounts/constraints.rs | 23 ------------- tests/swap/deps/openbook-dex | 1 + 4 files changed, 1 insertion(+), 60 deletions(-) create mode 160000 tests/swap/deps/openbook-dex diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs index ac7d30646b..e311cf9b4c 100644 --- a/lang/syn/src/codegen/accounts/constraints.rs +++ b/lang/syn/src/codegen/accounts/constraints.rs @@ -525,7 +525,6 @@ fn generate_constraint_init_group( owner, mint, token_program, - memo_transfer, } => { let token_program = match token_program { Some(t) => t.to_token_stream(), @@ -539,31 +538,12 @@ fn generate_constraint_init_group( let token_program_optional_check = check_scope.generate_check(&token_program); let rent_optional_check = check_scope.generate_check(rent); - // extension checks - let memo_transfer_check = match memo_transfer { - Some(gpa) => check_scope.generate_check(gpa), - None => quote! {}, - }; - let optional_checks = quote! { #system_program_optional_check #token_program_optional_check #rent_optional_check #owner_optional_check #mint_optional_check - #memo_transfer_check - }; - - let mut extensions = vec![]; - - if memo_transfer.is_some() { - extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MemoTransfer}); - } - - let extensions = if extensions.is_empty() { - quote! {Option::<&::anchor_spl::token_interface::ExtensionsVec>::None} - } else { - quote! {Option::<&::anchor_spl::token_interface::ExtensionsVec>::Some(&vec![#(#extensions),*])} }; let payer_optional_check = check_scope.generate_check(payer); @@ -593,21 +573,6 @@ fn generate_constraint_init_group( // Create the account with the system program. #create_account - if let Some(extensions) = #extensions { - for e in extensions { - match e { - ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MemoTransfer => { - ::anchor_spl::token_interface::memo_transfer_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::MemoTransfer { - token_program_id: #token_program.to_account_info(), - account: #field.to_account_info(), - owner: #owner.to_account_info(), - }))?; - }, - - } - } - } - // Initialize the token account. let cpi_program = #token_program.to_account_info(); let accounts = ::anchor_spl::token_interface::InitializeAccount3 { diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs index d7f1d21c84..0e086d3d75 100644 --- a/lang/syn/src/lib.rs +++ b/lang/syn/src/lib.rs @@ -756,7 +756,6 @@ pub enum ConstraintToken { TokenMint(Context), TokenAuthority(Context), TokenTokenProgram(Context), - ExtensionTransferMemo(Context), AssociatedTokenMint(Context), AssociatedTokenAuthority(Context), AssociatedTokenTokenProgram(Context), @@ -958,7 +957,6 @@ pub enum InitKind { owner: Expr, mint: Expr, token_program: Option, - memo_transfer: Option, }, AssociatedToken { owner: Expr, diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs index d47890511e..6734603592 100644 --- a/lang/syn/src/parser/accounts/constraints.rs +++ b/lang/syn/src/parser/accounts/constraints.rs @@ -319,12 +319,6 @@ pub fn parse_token(stream: ParseStream) -> ParseResult { token_program: stream.parse()?, }, )), - "transfer_memo" => ConstraintToken::ExtensionTransferMemo(Context::new( - span, - ConstraintBool { - enable: stream.parse()?, - }, - )), _ => return Err(ParseError::new(ident.span(), "Invalid attribute")), } } @@ -577,8 +571,6 @@ pub struct ConstraintGroupBuilder<'ty> { pub extension_interest_bearing_mint_rate: Option>, pub extension_interest_bearing_mint_authority: Option>, - // token extensions. - pub extension_memo_transfer: Option>, pub bump: Option>, pub program_seed: Option>, pub realloc: Option>, @@ -607,7 +599,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> { token_mint: None, token_authority: None, token_token_program: None, - extension_memo_transfer: None, associated_token_mint: None, associated_token_authority: None, associated_token_token_program: None, @@ -841,7 +832,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> { extension_permanent_delegate, extension_interest_bearing_mint_rate, extension_interest_bearing_mint_authority, - extension_memo_transfer, bump, program_seed, realloc, @@ -1022,7 +1012,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> { )), }, token_program: token_token_program.map(|tp| tp.into_inner().token_program), - memo_transfer: extension_memo_transfer.map(|mt| mt.into_inner().enable), } } else if let Some(at) = &associated_token { @@ -1104,7 +1093,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> { ConstraintToken::TokenAuthority(c) => self.add_token_authority(c), ConstraintToken::TokenMint(c) => self.add_token_mint(c), ConstraintToken::TokenTokenProgram(c) => self.add_token_token_program(c), - ConstraintToken::ExtensionTransferMemo(c) => self.add_extension_memo_transfer(c), ConstraintToken::AssociatedTokenAuthority(c) => self.add_associated_token_authority(c), ConstraintToken::AssociatedTokenMint(c) => self.add_associated_token_mint(c), ConstraintToken::AssociatedTokenTokenProgram(c) => { @@ -1441,17 +1429,6 @@ impl<'ty> ConstraintGroupBuilder<'ty> { Ok(()) } - fn add_extension_memo_transfer(&mut self, c: Context) -> ParseResult<()> { - if self.extension_memo_transfer.is_some() { - return Err(ParseError::new( - c.span(), - "extension memo transfer already provided", - )); - } - self.extension_memo_transfer.replace(c); - Ok(()) - } - fn add_associated_token_token_program( &mut self, c: Context, diff --git a/tests/swap/deps/openbook-dex b/tests/swap/deps/openbook-dex new file mode 160000 index 0000000000..5420646709 --- /dev/null +++ b/tests/swap/deps/openbook-dex @@ -0,0 +1 @@ +Subproject commit 5420646709df6edaaea90162d4f7476328077293 From 4864285e28401471544e52ebd06ec9dd2feadb07 Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Wed, 25 Sep 2024 17:27:59 -0400 Subject: [PATCH 11/13] remove submodule change --- tests/swap/deps/openbook-dex | 1 - 1 file changed, 1 deletion(-) delete mode 160000 tests/swap/deps/openbook-dex diff --git a/tests/swap/deps/openbook-dex b/tests/swap/deps/openbook-dex deleted file mode 160000 index 5420646709..0000000000 --- a/tests/swap/deps/openbook-dex +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5420646709df6edaaea90162d4f7476328077293 From 1a25d69167bc676a16a378a89ac8972c3e74f402 Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Mon, 14 Oct 2024 09:39:49 -0400 Subject: [PATCH 12/13] add test --- CHANGELOG.md | 1 + .../programs/token-extensions/src/instructions.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2607fadbd1..a28327afe4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,7 @@ The minor version will be incremented upon a breaking change and the patch versi - cli: Add completions command to generate shell completions via the clap_complete crate ([#3251](https://github.com/coral-xyz/anchor/pull/3251)). - cli: Always convert IDLs ([#3265](https://github.com/coral-xyz/anchor/pull/3265)). - cli: Check whether the `idl-build` feature exists when using the `idl build` command ([#3273](https://github.com/coral-xyz/anchor/pull/3273)). +- spl: Add 'Interest Bearing Config` Extension ([#3278](https://github.com/coral-xyz/anchor/pull/3278)). ### Fixes diff --git a/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs b/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs index a721120dc8..784bba2450 100644 --- a/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs +++ b/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs @@ -5,7 +5,7 @@ use anchor_spl::{ token_2022::spl_token_2022::extension::{ group_member_pointer::GroupMemberPointer, metadata_pointer::MetadataPointer, mint_close_authority::MintCloseAuthority, permanent_delegate::PermanentDelegate, - transfer_hook::TransferHook, + transfer_hook::TransferHook, interest_bearing_mint::{InterestBearingConfig, BasisPoints}, }, token_interface::{ get_mint_extension_data, spl_token_metadata_interface::state::TokenMetadata, @@ -53,6 +53,8 @@ pub struct CreateMintAccount<'info> { extensions::transfer_hook::program_id = crate::ID, extensions::close_authority::authority = authority, extensions::permanent_delegate::delegate = authority, + extensions::interest_bearing_mint::authority = authority, + extensions::interest_bearing_mint::rate = 100, )] pub mint: Box>, #[account( @@ -150,6 +152,12 @@ pub fn handler(ctx: Context, args: CreateMintAccountArgs) -> group_member_pointer.member_address, OptionalNonZeroPubkey::try_from(mint_key)? ); + let interest_bearing_config = get_mint_extension_data::(mint_data)?; + assert_eq!( + interest_bearing_config.rate_authority, + OptionalNonZeroPubkey::try_from(authority_key)? + ); + assert_eq!(interest_bearing_config.rate, BasisPoints::try_from(100)?); // transfer minimum rent to mint account update_account_lamports_to_minimum_balance( ctx.accounts.mint.to_account_info(), From c770ad82089cc78b76a5759b022e08803af9caa4 Mon Sep 17 00:00:00 2001 From: Bhargava Sai Macha Date: Mon, 21 Oct 2024 11:21:58 -0400 Subject: [PATCH 13/13] fix tests --- .../programs/token-extensions/src/instructions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs b/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs index 784bba2450..624461eb5b 100644 --- a/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs +++ b/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs @@ -157,7 +157,7 @@ pub fn handler(ctx: Context, args: CreateMintAccountArgs) -> interest_bearing_config.rate_authority, OptionalNonZeroPubkey::try_from(authority_key)? ); - assert_eq!(interest_bearing_config.rate, BasisPoints::try_from(100)?); + assert_eq!(interest_bearing_config.current_rate, BasisPoints::from(100)); // transfer minimum rent to mint account update_account_lamports_to_minimum_balance( ctx.accounts.mint.to_account_info(),