data_anchor_client/fees/
fee.rs

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