use std::str::FromStr;
use bigdecimal::BigDecimal;
use zera_proto::zera_api::BaseFeeResponse;
use zera_proto::zera_txn::{PublicKey, TransactionType};
use crate::error::{Result, ZeraError};
use crate::grpc::{UnaryTransport, ValidatorApiClient};
use crate::types::RpcConfig;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EnhancedBaseFeeResponse {
pub key_fee: String,
pub byte_fee: String,
pub new_wallet_fee: String,
pub key_fee_usd: String,
pub byte_fee_usd: String,
}
pub async fn get_base_fee(
txn_type: TransactionType,
public_key: Option<PublicKey>,
config: RpcConfig,
) -> Result<EnhancedBaseFeeResponse> {
let client = ValidatorApiClient::new(config)?;
get_base_fee_with_client(txn_type, public_key, &client).await
}
pub async fn get_base_fee_with_client<T>(
txn_type: TransactionType,
public_key: Option<PublicKey>,
client: &ValidatorApiClient<T>,
) -> Result<EnhancedBaseFeeResponse>
where
T: UnaryTransport,
{
let response = client
.get_base_fee(public_key, txn_type)
.await
.map_err(|error| {
ZeraError::Rpc(format!("Failed to get base fee from validator: {error}"))
})?;
enhance_base_fee_response(response)
}
pub fn enhance_base_fee_response(response: BaseFeeResponse) -> Result<EnhancedBaseFeeResponse> {
let key_fee = if response.key_fee.is_empty() {
"0".to_string()
} else {
response.key_fee.clone()
};
let byte_fee = if response.byte_fee.is_empty() {
"0".to_string()
} else {
response.byte_fee.clone()
};
let new_wallet_fee = if response.new_wallet_fee.is_empty() {
"0".to_string()
} else {
response.new_wallet_fee.clone()
};
Ok(EnhancedBaseFeeResponse {
key_fee_usd: decimal_ratio(&key_fee, "1000000000000000000")?,
byte_fee_usd: decimal_ratio(&byte_fee, "1000000000000000000")?,
key_fee,
byte_fee,
new_wallet_fee,
})
}
fn decimal_ratio(numerator: &str, denominator: &str) -> Result<String> {
let numerator = BigDecimal::from_str(numerator).map_err(|error| {
ZeraError::Serialization(format!("Invalid decimal \"{numerator}\": {error}"))
})?;
let denominator = BigDecimal::from_str(denominator).map_err(|error| {
ZeraError::Serialization(format!("Invalid decimal \"{denominator}\": {error}"))
})?;
Ok((numerator / denominator).normalized().to_string())
}