data_anchor_client/fees/
fee_strategy.rs

1use anchor_lang::prelude::Pubkey;
2use solana_client::nonblocking::rpc_client::RpcClient;
3use tracing::Instrument;
4
5use super::Lamports;
6use crate::{ChainError, DataAnchorClientResult, Fee, Priority, TransactionType};
7
8/// The strategy to use for calculating the fees for transactions.
9#[derive(Debug, Clone, Copy)]
10pub enum FeeStrategy {
11    /// Use a fixed fee for all transactions.
12    Fixed(Fee),
13    /// Calculate a reasonable fee based on the recent fees in the network and a given priority.
14    BasedOnRecentFees(Priority),
15}
16
17impl Default for FeeStrategy {
18    fn default() -> Self {
19        Self::BasedOnRecentFees(Priority::default())
20    }
21}
22
23impl From<Fee> for FeeStrategy {
24    fn from(fee: Fee) -> Self {
25        Self::Fixed(fee)
26    }
27}
28
29impl From<Priority> for FeeStrategy {
30    fn from(priority: Priority) -> Self {
31        Self::BasedOnRecentFees(priority)
32    }
33}
34
35impl FeeStrategy {
36    /// Converts a [`FeeStrategy`] into a [`Fee`] with the current compute unit price.
37    pub(crate) async fn convert_fee_strategy_to_fixed(
38        &self,
39        rpc_client: &RpcClient,
40        mutating_accounts: &[Pubkey],
41        tx_type: TransactionType,
42    ) -> DataAnchorClientResult<Fee> {
43        let priority = match self {
44            FeeStrategy::Fixed(fee) => {
45                // If the fee strategy is already fixed, return it as is.
46                return Ok(*fee);
47            }
48            FeeStrategy::BasedOnRecentFees(priority) => priority,
49        };
50
51        let mut fee_retries = 5;
52
53        while fee_retries > 0 {
54            let res = priority
55                .get_priority_fee_estimate(rpc_client, mutating_accounts)
56                .in_current_span()
57                .await;
58
59            match res {
60                Ok(fee) => {
61                    return Ok(Fee {
62                        prioritization_fee_rate: fee,
63                        num_signatures: tx_type.num_signatures(),
64                        compute_unit_limit: tx_type.compute_unit_limit(),
65                        price_per_signature: Lamports(5000),
66                        blob_account_size: 0,
67                    });
68                }
69                Err(e) => {
70                    fee_retries -= 1;
71                    if fee_retries == 0 {
72                        return Err(e);
73                    }
74                }
75            }
76        }
77
78        Err(ChainError::ConversionError("Fee strategy conversion failed after retries").into())
79    }
80}