Skip to content

Commit

Permalink
add metadata check
Browse files Browse the repository at this point in the history
  • Loading branch information
solonk8 committed Mar 7, 2024
1 parent 8b0ea09 commit c414ed6
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 5 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions programs/mmm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mpl-token-metadata = { version = "4.0.0" }
open_creator_protocol = { version = "0.4.2", features = ["cpi"] }
solana-program = "~1.17"
spl-token-group-interface = "0.1.0"
spl-token-metadata-interface = "0.2.0"
spl-token = { version = "4.0.0", features = ["no-entrypoint"] }
spl-associated-token-account = { version = "2.2.0", features = [
"no-entrypoint",
Expand Down
83 changes: 79 additions & 4 deletions programs/mmm/src/ext_util.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,93 @@
use anchor_lang::prelude::*;
use solana_program::{account_info::AccountInfo, pubkey::Pubkey};
use spl_token_2022::{
extension::{
group_member_pointer::GroupMemberPointer, BaseStateWithExtensions, StateWithExtensions,
group_member_pointer::GroupMemberPointer, metadata_pointer::MetadataPointer,
BaseStateWithExtensions, StateWithExtensions,
},
state::Mint as Token22Mint,
};
use spl_token_group_interface::state::TokenGroupMember;
use spl_token_metadata_interface::state::TokenMetadata;

use crate::state::{Allowlist, ALLOWLIST_KIND_GROUP};
use crate::{errors::MMMErrorCode, state::*};

use {crate::errors::MMMErrorCode, anchor_lang::prelude::*};
pub fn check_allowlists_for_mint_ext(
allowlists: &[Allowlist],
token_mint: &AccountInfo,
allowlist_aux: Option<String>,
) -> Result<TokenMetadata> {
if token_mint.owner != &spl_token_2022::ID || token_mint.data_is_empty() {
return Err(MMMErrorCode::InvalidTokenMint.into());
}
let borrowed_data = token_mint.data.borrow();
let mint_deserialized = StateWithExtensions::<Token22Mint>::unpack(&borrowed_data)?;
if !mint_deserialized.base.is_initialized {
return Err(MMMErrorCode::InvalidTokenMint.into());
}
if let Ok(metadata_ptr) = mint_deserialized.get_extension::<MetadataPointer>() {
if Option::<Pubkey>::from(metadata_ptr.metadata_address) != Some(*token_mint.key) {
return Err(MMMErrorCode::InValidTokenExtension.into());
}
}
let parsed_metadata = mint_deserialized
.get_variable_len_extension::<TokenMetadata>()
.unwrap();

if allowlists
.iter()
.any(|&val| val.kind == ALLOWLIST_KIND_METADATA)
{
// If allowlist_aux is not passed in, do not validate URI.
if let Some(ref aux_key) = allowlist_aux {
// Handle URI padding.
if !parsed_metadata.uri.trim().starts_with(aux_key) {
msg!(
"Failed metadata validation. Expected URI: |{}| but got |{}|",
*aux_key,
parsed_metadata.uri
);
return Err(MMMErrorCode::UnexpectedMetadataUri.into());
}
}
}

for allowlist_val in allowlists.iter() {
match allowlist_val.kind {
ALLOWLIST_KIND_EMPTY => {}
ALLOWLIST_KIND_ANY => {
// any is a special case, we don't need to check anything else
return Ok(parsed_metadata);
}
ALLOWLIST_KIND_FVCA => {
return Err(MMMErrorCode::InvalidAllowLists.into());
}
ALLOWLIST_KIND_MINT => {
if token_mint.key() == allowlist_val.value {
return Ok(parsed_metadata);
}
}
ALLOWLIST_KIND_MCC => {
return Err(MMMErrorCode::InvalidAllowLists.into());
}
ALLOWLIST_KIND_METADATA | ALLOWLIST_KIND_GROUP => {
// Do not validate URI here, as we already did it above.
// Group is validated in a separate function.
// These checks are separate since allowlist values are unioned together.
continue;
}
_ => {
return Err(MMMErrorCode::InvalidAllowLists.into());
}
}
}

// at the end, we didn't find a match, thus return err
Err(MMMErrorCode::InvalidAllowLists.into())
}

pub fn check_group_ext_for_mint(token_mint: &AccountInfo, allowlists: &[Allowlist]) -> Result<()> {
if token_mint.data_is_empty() {
if token_mint.owner != &spl_token_2022::ID || token_mint.data_is_empty() {
return Err(MMMErrorCode::InvalidTokenMint.into());
}
let borrowed_data = token_mint.data.borrow();
Expand Down
14 changes: 13 additions & 1 deletion programs/mmm/src/instructions/ext_vanilla/ext_deposit_sell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ use spl_token_2022::onchain::invoke_transfer_checked;
use crate::{
constants::*,
errors::MMMErrorCode,
ext_util::check_group_ext_for_mint,
ext_util::{check_allowlists_for_mint_ext, check_group_ext_for_mint},
instructions::check_allowlists_for_mint,
state::{Pool, SellState},
util::log_pool,
};

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct ExtDepositeSellArgs {
pub asset_amount: u64,
pub allowlist_aux: Option<String>,
}

#[derive(Accounts)]
Expand All @@ -33,6 +35,10 @@ pub struct ExtDepositeSell<'info> {
bump
)]
pub pool: Box<Account<'info, Pool>>,
#[account(
mint::token_program = token_program,
constraint = asset_mint.supply == 1 && asset_mint.decimals == 0 @ MMMErrorCode::InvalidTokenMint,
)]
pub asset_mint: InterfaceAccount<'info, Mint>,
#[account(
mut,
Expand Down Expand Up @@ -83,7 +89,13 @@ pub fn handler<'info>(
return Err(MMMErrorCode::InvalidAccountState.into());
}

check_allowlists_for_mint_ext(
&pool.allowlists,
&asset_mint.to_account_info(),
args.allowlist_aux,
)?;
check_group_ext_for_mint(&asset_mint.to_account_info(), &pool.allowlists)?;

invoke_transfer_checked(
token_program.key,
asset_token_account.to_account_info(),
Expand Down

0 comments on commit c414ed6

Please sign in to comment.