gmsol_solana_utils/
compute_budget.rs

1use std::ops::AddAssign;
2
3use solana_sdk::{compute_budget::ComputeBudgetInstruction, instruction::Instruction};
4
5/// Compute Budget.
6#[derive(Debug, Clone, Copy)]
7pub struct ComputeBudget {
8    min_priority_lamports: Option<u64>,
9    limit_units: u32,
10    price_micro_lamports: u64,
11}
12
13impl Default for ComputeBudget {
14    fn default() -> Self {
15        Self {
16            min_priority_lamports: Some(Self::DEFAULT_MIN_PRIORITY_LAMPORTS),
17            limit_units: 200_000,
18            price_micro_lamports: 50_000,
19        }
20    }
21}
22
23impl ComputeBudget {
24    const MICRO_LAMPORTS: u64 = 10u64.pow(6);
25
26    /// Minimum priority lamports.
27    pub const DEFAULT_MIN_PRIORITY_LAMPORTS: u64 = 10000;
28
29    /// Max compute unit.
30    pub const MAX_COMPUTE_UNIT: u32 = 1_400_000;
31
32    /// Set compute units limit.
33    #[inline]
34    pub fn with_limit(mut self, units: u32) -> Self {
35        self.set_limit(units);
36        self
37    }
38
39    /// Set compute unit price.
40    #[inline]
41    pub fn with_price(mut self, micro_lamports: u64) -> Self {
42        self.set_price(micro_lamports);
43        self
44    }
45
46    /// Set min priority lamports.
47    #[inline]
48    pub fn with_min_priority_lamports(mut self, lamports: Option<u64>) -> Self {
49        self.set_min_priority_lamports(lamports);
50        self
51    }
52
53    /// Set min priority lamports.
54    #[inline]
55    pub fn set_min_priority_lamports(&mut self, lamports: Option<u64>) -> &mut Self {
56        self.min_priority_lamports = lamports;
57        self
58    }
59
60    /// Set compute unit price.
61    pub fn set_price(&mut self, micro_lamports: u64) -> &mut Self {
62        self.price_micro_lamports = micro_lamports;
63        self
64    }
65
66    /// Set compute unit limit.
67    pub fn set_limit(&mut self, units: u32) -> &mut Self {
68        self.limit_units = units;
69        self
70    }
71
72    fn budget_price(&self, compute_unit_price_micro_lamports: Option<u64>) -> u64 {
73        let mut price = compute_unit_price_micro_lamports.unwrap_or(self.price_micro_lamports);
74        if let Some(min_price) = self.min_priority_lamports.and_then(|min_lamports| {
75            min_lamports
76                .checked_mul(Self::MICRO_LAMPORTS)?
77                .checked_div(self.budget_units() as u64)
78        }) {
79            price = price.max(min_price)
80        }
81        price
82    }
83
84    fn budget_units(&self) -> u32 {
85        self.limit_units.min(Self::MAX_COMPUTE_UNIT)
86    }
87
88    /// Build compute budget instructions.
89    pub fn compute_budget_instructions(
90        &self,
91        compute_unit_price_micro_lamports: Option<u64>,
92    ) -> Vec<Instruction> {
93        let price = self.budget_price(compute_unit_price_micro_lamports);
94        vec![
95            ComputeBudgetInstruction::set_compute_unit_limit(self.budget_units()),
96            ComputeBudgetInstruction::set_compute_unit_price(price),
97        ]
98    }
99
100    /// Get compute unit limit.
101    pub fn limit(&self) -> u32 {
102        self.limit_units
103    }
104
105    /// Get compute unit price in mciro lamports.
106    pub fn price(&self) -> u64 {
107        self.price_micro_lamports
108    }
109
110    /// Estimate priority fee.
111    pub fn fee(&self, compute_unit_price_micro_lamports: Option<u64>) -> u64 {
112        self.budget_units() as u64 * self.budget_price(compute_unit_price_micro_lamports)
113            / Self::MICRO_LAMPORTS
114    }
115}
116
117impl AddAssign for ComputeBudget {
118    fn add_assign(&mut self, rhs: Self) {
119        self.limit_units += rhs.limit_units;
120        self.price_micro_lamports = self.price_micro_lamports.max(rhs.price_micro_lamports);
121        let min_lamports = match (self.min_priority_lamports, rhs.min_priority_lamports) {
122            (Some(lamports), None) => Some(lamports),
123            (None, Some(lamports)) => Some(lamports),
124            (Some(lhs), Some(rhs)) => Some(lhs.max(rhs)),
125            (None, None) => None,
126        };
127        self.min_priority_lamports = min_lamports;
128    }
129}