data_anchor_client/fees/
fee.rs

1use anchor_lang::prelude::Rent;
2
3use super::{Lamports, MicroLamports};
4
5/// The expected fees for a blob upload, broken down by source.
6#[derive(Debug, Copy, Clone)]
7pub struct Fee {
8    /// The number of signatures required, summed across all transactions.
9    pub num_signatures: u16,
10    /// The price per signature, in lamports. 5000 lamports by default.
11    pub price_per_signature: Lamports,
12    /// The compute unit limit, summed across all transactions.
13    pub compute_unit_limit: u32,
14    /// The prioritization fee rate, in micro-lamports.
15    pub prioritization_fee_rate: MicroLamports,
16    /// The required size of the blober account, in bytes.
17    pub blob_account_size: usize,
18}
19
20impl Fee {
21    pub const ZERO: Fee = Fee {
22        num_signatures: 0,
23        price_per_signature: Lamports::ZERO,
24        compute_unit_limit: 0,
25        prioritization_fee_rate: MicroLamports::ZERO,
26        blob_account_size: 0,
27    };
28
29    /// Calculate the static part of the fee for a blob upload.
30    /// It is proportional to the number of signatures.
31    pub fn static_fee(&self) -> Lamports {
32        self.price_per_signature
33            .checked_mul(self.num_signatures as u32)
34            .expect("multiplication overflow")
35    }
36
37    /// Calculate the recommended prioritization fee for a blob upload at the given priority.
38    /// It is proportional to the compute unit limit, *not* the actual consumed compute units.
39    /// The value is rounded up to the nearest lamport.
40    pub fn prioritization_fee(&self) -> Lamports {
41        self.prioritization_fee_rate
42            .checked_mul(self.compute_unit_limit as u64)
43            .expect("multiplication overflow")
44            .try_into()
45            .expect("failed to convert from micro-lamports to lamports")
46    }
47
48    /// Calculate the total fee for a blob upload, including the static fee and the prioritization fee.
49    /// Does not include rent.
50    pub fn total_fee(&self) -> Lamports {
51        self.static_fee()
52            .checked_add(self.prioritization_fee())
53            .expect("addition overflow")
54    }
55
56    /// Calculate the required rent used as a deposit for the blober account.
57    /// Solana programs must hold on to a certain amount of lamports (SOL) in order to exist on-chain.
58    /// This rent is paid upfront whenever an account is created or resized, and is proportional to
59    /// the size of the account.
60    pub fn rent(&self) -> Lamports {
61        let minimum_balance = Rent::default().minimum_balance(self.blob_account_size) as u32;
62        Lamports::new(minimum_balance)
63    }
64}
65
66#[cfg(test)]
67mod tests {
68    use super::*;
69
70    #[test]
71    fn less_than_one_lamport_prioritization_fee_is_ok() {
72        let fee = Fee {
73            num_signatures: 1,
74            price_per_signature: Lamports::new(5000),
75            compute_unit_limit: 1,
76            prioritization_fee_rate: MicroLamports::new(999_999),
77            blob_account_size: 100,
78        };
79        assert_eq!(fee.prioritization_fee(), Lamports::new(1));
80    }
81}