crate_token/
state.rs

1use anchor_lang::{prelude::*, solana_program::pubkey::PUBKEY_BYTES};
2use num_traits::ToPrimitive;
3use vipers::unwrap_int;
4
5/// Contains the info of a crate token. Immutable.
6/// The account associated with this struct is also the mint/freeze authority.
7#[account]
8#[derive(Copy, Debug, Default, PartialEq, Eq)]
9pub struct CrateToken {
10    /// [anchor_spl::token::Mint] of the [CrateToken].
11    pub mint: Pubkey,
12    /// Bump.
13    pub bump: u8,
14
15    /// Authority that can modify the [CrateToken]'s fees.
16    pub fee_setter_authority: Pubkey,
17    /// Authority that can modify who can change the fees.
18    pub fee_to_setter: Pubkey,
19    /// Authority that is allowed to issue new shares of the Crate.
20    /// This is usually a program that will handle users depositing
21    /// tokens into the crate + giving them shares of the crate.
22    pub issue_authority: Pubkey,
23    /// Authority that is allowed to withdraw any token from the Crate.
24    /// Withdrawals may be subject to fees.
25    pub withdraw_authority: Pubkey,
26
27    /// Account which is the recipient of issue/withdraw ("author") fees.
28    /// If fees do not exist, this is unused.
29    pub author_fee_to: Pubkey,
30
31    /// The issuance fee in bps.
32    /// [crate::ISSUE_FEE_BPS] of this fee goes to the Crate DAO.
33    pub issue_fee_bps: u16,
34    /// The issuance fee in bps.
35    /// [crate::WITHDRAW_FEE_BPS] of this fee goes to the Crate DAO.
36    pub withdraw_fee_bps: u16,
37}
38
39impl CrateToken {
40    pub const LEN: usize = PUBKEY_BYTES + 1 + PUBKEY_BYTES * 5 + 2 + 2;
41}
42
43#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
44pub struct Fees {
45    pub amount: u64,
46    /// Fee to the Crate's author.
47    pub author_fee: u64,
48    /// Fee to the Crate protocol.
49    pub protocol_fee: u64,
50}
51
52fn apply_bps(amount: u64, bps: u16) -> Result<(u64, u64)> {
53    let bps = unwrap_int!((amount)
54        .checked_mul(bps.into())
55        .and_then(|v| v.checked_div(10_000))
56        .and_then(|v| v.to_u64()));
57    Ok((unwrap_int!(amount.checked_sub(bps)), bps))
58}
59
60impl CrateToken {
61    /// Applies the issuance fee.
62    pub fn apply_issue_fee(&self, amount: u64) -> Result<Fees> {
63        let (amount, issue_fee) = apply_bps(amount, self.issue_fee_bps)?;
64        let (author_fee, protocol_fee) = apply_bps(issue_fee, crate::ISSUE_FEE_BPS)?;
65        Ok(Fees {
66            amount,
67            author_fee,
68            protocol_fee,
69        })
70    }
71
72    /// Applies the withdraw fee.
73    pub fn apply_withdraw_fee(&self, amount: u64) -> Result<Fees> {
74        let (amount, withdraw_fee) = apply_bps(amount, self.withdraw_fee_bps)?;
75        let (author_fee, protocol_fee) = apply_bps(withdraw_fee, crate::WITHDRAW_FEE_BPS)?;
76        Ok(Fees {
77            amount,
78            author_fee,
79            protocol_fee,
80        })
81    }
82}
83
84#[cfg(test)]
85mod tests {
86    use super::*;
87
88    #[test]
89    fn test_crate_token_len() {
90        use crate::CrateToken;
91        assert_eq!(
92            CrateToken::LEN,
93            CrateToken::default().try_to_vec().unwrap().len()
94        );
95    }
96}