1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
use solana_program::{account_info::AccountInfo, program_error::ProgramError, pubkey::Pubkey};

use crate::{
    error::MetadataError,
    state::{UseAuthorityRecord, UseMethod, Uses, PREFIX, USER},
    utils::assert_derivation,
};

pub fn assert_valid_use(
    incoming_use: &Option<Uses>,
    current_use: &Option<Uses>,
) -> Result<(), ProgramError> {
    if let Some(i) = incoming_use {
        if i.use_method == UseMethod::Single && (i.total != 1 || i.remaining != 1) {
            return Err(MetadataError::InvalidUseMethod.into());
        }
        if i.use_method == UseMethod::Multiple && i.total < 2 {
            return Err(MetadataError::InvalidUseMethod.into());
        }
    }
    return match (incoming_use, current_use) {
        (Some(incoming), Some(current)) => {
            if incoming.use_method != current.use_method && current.total != current.remaining {
                return Err(MetadataError::CannotChangeUseMethodAfterFirstUse.into());
            }
            if incoming.total != current.total && current.total != current.remaining {
                return Err(MetadataError::CannotChangeUsesAfterFirstUse.into());
            }
            if incoming.remaining != current.remaining && current.total != current.remaining {
                return Err(MetadataError::CannotChangeUsesAfterFirstUse.into());
            }
            Ok(())
        }
        _ => Ok(()),
    };
}

pub fn assert_valid_bump(
    canonical_bump: u8,
    use_authority_record: &UseAuthorityRecord,
) -> Result<(), ProgramError> {
    if canonical_bump != use_authority_record.bump {
        return Err(MetadataError::InvalidUseAuthorityRecord.into());
    }
    Ok(())
}

pub fn assert_use_authority_derivation(
    program_id: &Pubkey,
    use_authority_record_info: &AccountInfo,
    user_info: &AccountInfo,
    mint_info: &AccountInfo,
) -> Result<u8, ProgramError>{
    let use_authority_seeds = [
        PREFIX.as_bytes(),
        program_id.as_ref(),
        &mint_info.key.as_ref(),
        USER.as_bytes(),
        &user_info.key.as_ref(),
    ];
    assert_derivation(&program_id, use_authority_record_info, &use_authority_seeds)
}

pub fn process_use_authority_validation(
    data_len: usize,
    must_be_empty: bool,
) -> Result<(), ProgramError> {
    let record_info_empty = data_len == 0;
    if must_be_empty {
        if !record_info_empty {
            return Err(MetadataError::UseAuthorityRecordAlreadyExists.into());
        }
    } else {
        if record_info_empty {
            return Err(MetadataError::UseAuthorityRecordAlreadyRevoked.into());
        }
    }
    Ok(())
}