Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions lang/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,32 @@ pub enum ErrorCode {
/// 2042 - Account must be migrated before exiting
#[msg("Account must be migrated before exiting")]
AccountNotMigrated,
/// Extension constraints - cont.
///
/// 2043 - A non-transferable extension constraint was violated
#[msg("A non-transferable extension constraint was violated")]
ConstraintMintNonTransferableExtension,
/// 2044 - A transfer fee extension constraint was violated
#[msg("A transfer fee extension constraint was violated")]
ConstraintMintTransferFeeExtension,
/// 2045 - A transfer fee extension config authority constraint was violated
#[msg("A transfer fee extension config authority constraint was violated")]
ConstraintMintTransferFeeConfigAuthority,
/// 2046 - A transfer fee extension withheld authority constraint was violated
#[msg("A transfer fee extension withheld authority constraint was violated")]
ConstraintMintTransferFeeWithheldAuthority,
/// 2047 - An interest bearing extension constraint was violated
#[msg("An interest bearing extension constraint was violated")]
ConstraintMintInterestBearingExtension,
/// 2048 - An interest bearing extension rate authority constraint was violated
#[msg("An interest bearing extension rate authority constraint was violated")]
ConstraintMintInterestBearingRateAuthority,
/// 2049 - A default account state extension constraint was violated
#[msg("A default account state extension constraint was violated")]
ConstraintMintDefaultAccountStateExtension,
/// 2050 - A default account state extension state constraint was violated
#[msg("A default account state extension state constraint was violated")]
ConstraintMintDefaultAccountState,

// Require
/// 2500 - A require expression was violated
Expand Down
2 changes: 1 addition & 1 deletion lang/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub use {
anchor_attribute_event::{emit, event},
anchor_attribute_program::{declare_program, instruction, program},
anchor_derive_accounts::Accounts,
anchor_derive_serde::{__erase, AnchorDeserialize, AnchorSerialize},
anchor_derive_serde::{AnchorDeserialize, AnchorSerialize, __erase},
anchor_derive_space::InitSpace,
borsh::ser::BorshSerialize as AnchorSerialize,
const_crypto::ed25519::derive_program_address,
Expand Down
230 changes: 230 additions & 0 deletions lang/syn/src/codegen/accounts/constraints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,14 @@ fn generate_constraint_init_group(
permanent_delegate,
transfer_hook_authority,
transfer_hook_program_id,
non_transferable,
transfer_fee_config_authority,
transfer_fee_withheld_authority,
transfer_fee_basis_points,
transfer_fee_max_fee,
interest_bearing_authority,
interest_bearing_rate,
default_account_state,
} => {
let token_program = match token_program {
Some(t) => t.to_token_stream(),
Expand Down Expand Up @@ -833,6 +841,41 @@ fn generate_constraint_init_group(
None => quote! {},
};

let transfer_fee_config_authority_check = match transfer_fee_config_authority {
Some(tfca) => check_scope.generate_check(tfca),
None => quote! {},
};

let transfer_fee_withheld_authority_check = match transfer_fee_withheld_authority {
Some(tfwa) => check_scope.generate_check(tfwa),
None => quote! {},
};

let transfer_fee_basis_points_check = match transfer_fee_basis_points {
Some(tfbp) => check_scope.generate_check(tfbp),
None => quote! {},
};

let transfer_fee_max_fee_check = match transfer_fee_max_fee {
Some(tfmf) => check_scope.generate_check(tfmf),
None => quote! {},
};

let interest_bearing_authority_check = match interest_bearing_authority {
Some(iba) => check_scope.generate_check(iba),
None => quote! {},
};

let interest_bearing_rate_check = match interest_bearing_rate {
Some(ibr) => check_scope.generate_check(ibr),
None => quote! {},
};

let default_account_state_check = match default_account_state {
Some(das) => check_scope.generate_check(das),
None => quote! {},
};

let system_program_optional_check = check_scope.generate_check(system_program);
let token_program_optional_check = check_scope.generate_check(&token_program);
let rent_optional_check = check_scope.generate_check(rent);
Expand All @@ -853,6 +896,13 @@ fn generate_constraint_init_group(
#transfer_hook_authority_check
#transfer_hook_program_id_check
#permanent_delegate_check
#transfer_fee_config_authority_check
#transfer_fee_withheld_authority_check
#transfer_fee_basis_points_check
#transfer_fee_max_fee_check
#interest_bearing_authority_check
#interest_bearing_rate_check
#default_account_state_check
};

let payer_optional_check = check_scope.generate_check(payer);
Expand Down Expand Up @@ -884,6 +934,26 @@ fn generate_constraint_init_group(
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::PermanentDelegate});
}

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

if transfer_fee_config_authority.is_some()
|| transfer_fee_withheld_authority.is_some()
|| transfer_fee_basis_points.is_some()
|| transfer_fee_max_fee.is_some()
{
extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::TransferFeeConfig});
}

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

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

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

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

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

let transfer_fee_basis_points = match transfer_fee_basis_points {
Some(tfbp) => quote! { Option::<u16>::Some(#tfbp) },
None => quote! { Option::<u16>::None },
};

let transfer_fee_max_fee = match transfer_fee_max_fee {
Some(tfmf) => quote! { Option::<u64>::Some(#tfmf) },
None => quote! { Option::<u64>::None },
};

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

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

let default_account_state = match default_account_state {
Some(das) => {
quote! { Option::<anchor_spl::token_2022::spl_token_2022::state::AccountState>::Some(#das) }
}
None => {
quote! { Option::<anchor_spl::token_2022::spl_token_2022::state::AccountState>::None }
}
};

let create_account = generate_create_account(
field,
mint_space,
Expand Down Expand Up @@ -1028,6 +1137,38 @@ fn generate_constraint_init_group(
mint: #field.to_account_info(),
}), #permanent_delegate.unwrap())?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::NonTransferable => {
::anchor_spl::token_interface::non_transferable_mint_initialize(anchor_lang::context::CpiContext::new(cpi_program_id, ::anchor_spl::token_interface::NonTransferableMintInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
}))?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::TransferFeeConfig => {
::anchor_spl::token_interface::transfer_fee_initialize(anchor_lang::context::CpiContext::new(cpi_program_id, ::anchor_spl::token_interface::TransferFeeInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
}),
#transfer_fee_config_authority.as_ref(),
#transfer_fee_withheld_authority.as_ref(),
#transfer_fee_basis_points.unwrap(),
#transfer_fee_max_fee.unwrap(),
)?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::InterestBearingConfig => {
::anchor_spl::token_interface::interest_bearing_mint_initialize(anchor_lang::context::CpiContext::new(cpi_program_id, ::anchor_spl::token_interface::InterestBearingMintInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
}),
#interest_bearing_authority,
#interest_bearing_rate.unwrap(),
)?;
},
::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::DefaultAccountState => {
::anchor_spl::token_interface::default_account_state_initialize(anchor_lang::context::CpiContext::new(cpi_program_id, ::anchor_spl::token_interface::DefaultAccountStateInitialize {
token_program_id: #token_program.to_account_info(),
mint: #field.to_account_info(),
}), #default_account_state.as_ref().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 Expand Up @@ -1588,6 +1729,90 @@ fn generate_constraint_mint(
None => quote! {},
};

let non_transferable_check = match &c.non_transferable {
Some(_) => {
quote! {
let non_transferable = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::non_transferable::NonTransferable>(#account_ref);
if non_transferable.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintNonTransferableExtension.into());
}
}
}
None => quote! {},
};

let transfer_fee_config_authority_check = match &c.transfer_fee_config_authority {
Some(transfer_fee_config_authority) => {
let transfer_fee_config_authority_optional_check =
optional_check_scope.generate_check(transfer_fee_config_authority);
quote! {
let transfer_fee = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::transfer_fee::TransferFeeConfig>(#account_ref);
if transfer_fee.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferFeeExtension.into());
}
#transfer_fee_config_authority_optional_check
if transfer_fee.unwrap().transfer_fee_config_authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#transfer_fee_config_authority.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferFeeConfigAuthority.into());
}
}
}
None => quote! {},
};

let transfer_fee_withheld_authority_check = match &c.transfer_fee_withheld_authority {
Some(transfer_fee_withheld_authority) => {
let transfer_fee_withheld_authority_optional_check =
optional_check_scope.generate_check(transfer_fee_withheld_authority);
quote! {
let transfer_fee = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::transfer_fee::TransferFeeConfig>(#account_ref);
if transfer_fee.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferFeeExtension.into());
}
#transfer_fee_withheld_authority_optional_check
if transfer_fee.unwrap().withdraw_withheld_authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#transfer_fee_withheld_authority.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferFeeWithheldAuthority.into());
}
}
}
None => quote! {},
};

let interest_bearing_authority_check = match &c.interest_bearing_authority {
Some(interest_bearing_authority) => {
let interest_bearing_authority_optional_check =
optional_check_scope.generate_check(interest_bearing_authority);
quote! {
let interest_bearing = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::interest_bearing_mint::InterestBearingConfig>(#account_ref);
if interest_bearing.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintInterestBearingExtension.into());
}
#interest_bearing_authority_optional_check
if interest_bearing.unwrap().rate_authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#interest_bearing_authority.key()))? {
return Err(anchor_lang::error::ErrorCode::ConstraintMintInterestBearingRateAuthority.into());
}
}
}
None => quote! {},
};

let default_account_state_check = match &c.default_account_state {
Some(default_account_state) => {
let default_account_state_optional_check =
optional_check_scope.generate_check(default_account_state);
quote! {
let account_state = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::default_account_state::DefaultAccountState>(#account_ref);
if account_state.is_err() {
return Err(anchor_lang::error::ErrorCode::ConstraintMintDefaultAccountStateExtension.into());
}
#default_account_state_optional_check
if account_state.unwrap().state != #default_account_state as u8 {
return Err(anchor_lang::error::ErrorCode::ConstraintMintDefaultAccountState.into());
}
}
}
None => quote! {},
};

quote! {
{
#decimal_check
Expand All @@ -1604,6 +1829,11 @@ fn generate_constraint_mint(
#permanent_delegate_check
#transfer_hook_authority_check
#transfer_hook_program_id_check
#non_transferable_check
#transfer_fee_config_authority_check
#transfer_fee_withheld_authority_check
#interest_bearing_authority_check
#default_account_state_check
}
}
}
Expand Down
Loading