whisky_pallas/utils/
fee.rs

1use pallas::ledger::primitives::Fragment;
2use whisky_common::{Protocol, WError};
3
4use crate::wrapper::transaction_body::Transaction;
5
6pub fn calculate_fee(
7    transaction: Transaction,
8    script_size: usize,
9    protocol_params: Protocol,
10) -> Result<u64, WError> {
11    let witness_set = &transaction.inner.transaction_witness_set;
12    let fee = protocol_params.min_fee_b
13        + transaction
14            .inner
15            .encode_fragment()
16            .map_err(|_| {
17                WError::new(
18                    "Calculating Fee - ",
19                    "Error while serializing TransactionBody",
20                )
21            })?
22            .len() as u64
23            * protocol_params.min_fee_a;
24    let script_ref_fee = calculate_script_ref_fee(
25        script_size,
26        protocol_params.min_fee_ref_script_cost_per_byte,
27    );
28    let Some(redeemers) = &witness_set.redeemer else {
29        return Ok(fee + script_ref_fee);
30    };
31    let script_fee = match redeemers.clone().unwrap() {
32        pallas::ledger::primitives::conway::Redeemers::List(redeemers) => {
33            let mut script_fee: f64 = 0.0;
34            for redeemer in redeemers {
35                let mem_units = redeemer.ex_units.mem;
36                let step_units = redeemer.ex_units.steps;
37                script_fee += mem_units as f64 * protocol_params.price_mem;
38                script_fee += step_units as f64 * protocol_params.price_step;
39            }
40            script_fee.ceil() as u64
41        }
42        pallas::ledger::primitives::conway::Redeemers::Map(btree_map) => {
43            let mut script_fee: f64 = 0.0;
44            for (_, redeemer) in btree_map {
45                let mem_units = redeemer.ex_units.mem;
46                let step_units = redeemer.ex_units.steps;
47                script_fee += mem_units as f64 * protocol_params.price_mem;
48                script_fee += step_units as f64 * protocol_params.price_step;
49            }
50            script_fee.ceil() as u64
51        }
52    };
53    Ok(fee + script_fee + script_ref_fee)
54}
55
56fn calculate_script_ref_fee(script_size: usize, min_fee_ref_script_cost_per_byte: u64) -> u64 {
57    let mut script_fee: f64 = 0.0;
58    const TIER_SIZE: u64 = 25600;
59    const TIER_MULTIPLIER: f64 = 1.2;
60
61    let mut current_multiplier: f64 = 1.0;
62    let mut remaining_size = script_size as u64;
63    while remaining_size >= TIER_SIZE {
64        script_fee +=
65            TIER_SIZE as f64 * current_multiplier * min_fee_ref_script_cost_per_byte as f64;
66        remaining_size -= TIER_SIZE;
67        current_multiplier *= TIER_MULTIPLIER;
68    }
69    if remaining_size > 0 {
70        script_fee +=
71            remaining_size as f64 * current_multiplier * min_fee_ref_script_cost_per_byte as f64;
72    }
73    script_fee.ceil() as u64
74}