token_acl_client/
metadata.rs

1use std::str::FromStr;
2
3use solana_instruction::Instruction;
4use solana_pubkey::Pubkey;
5use spl_token_client::spl_token_2022::{
6    extension::{BaseStateWithExtensions, PodStateWithExtensions},
7    pod::PodMint,
8};
9use spl_token_metadata_interface::state::{Field, TokenMetadata};
10use token_acl_interface::error::ThawFreezeGateError;
11
12pub const TOKEN_ACL_METADATA_KEY: &str = "token_acl";
13
14pub fn set_mint_tacl_metadata_ix(
15    mint: &Pubkey,
16    metadata_authority: &Pubkey,
17    gating_program: &Pubkey,
18) -> Instruction {
19    spl_token_metadata_interface::instruction::update_field(
20        &spl_token_client::spl_token_2022::ID,
21        mint,
22        metadata_authority,
23        Field::Key(TOKEN_ACL_METADATA_KEY.to_string()),
24        gating_program.to_string(),
25    )
26}
27
28pub fn get_gating_program_from_mint_data(data: &[u8]) -> Result<Pubkey, ThawFreezeGateError> {
29    let mint = PodStateWithExtensions::<PodMint>::unpack(data)
30        .map_err(|_| ThawFreezeGateError::InvalidTokenMint)?;
31
32    let metadata = mint
33        .get_variable_len_extension::<TokenMetadata>()
34        .map_err(|_| ThawFreezeGateError::InvalidTokenMint)?;
35
36    let gating_program = metadata
37        .additional_metadata
38        .iter()
39        .find(|(key, _)| key == TOKEN_ACL_METADATA_KEY)
40        .map(|(_, val)| val)
41        .ok_or(ThawFreezeGateError::InvalidTokenMint)?;
42
43    Pubkey::from_str(&gating_program).map_err(|_| ThawFreezeGateError::InvalidTokenMint)
44}
45
46#[cfg(feature = "fetch")]
47pub fn get_gating_program_from_mint(
48    rpc: &solana_client::rpc_client::RpcClient,
49    mint_pubkey: &Pubkey,
50) -> Result<Pubkey, ThawFreezeGateError> {
51    let account = rpc
52        .get_account(mint_pubkey)
53        .map_err(|_| ThawFreezeGateError::InvalidTokenMint)?;
54
55    get_gating_program_from_mint_data(&account.data)
56}