use std::cmp::max;
use zcash_primitives::transaction::fees::zip317::{GRACE_ACTIONS, MARGINAL_FEE};
use zcash_protocol::{PoolType, ShieldedPool};
#[must_use]
pub fn one_to_one(
source_protocol: Option<ShieldedPool>,
target_pool: PoolType,
mut change: bool,
) -> u64 {
if source_protocol.is_none() && target_pool == PoolType::TRANSPARENT {
change = false;
}
let transparent_inputs: usize = 0;
let mut transparent_outputs: usize = 0;
let mut sapling_inputs: usize = 0;
let mut sapling_outputs: usize = 0;
let mut orchard_inputs: usize = 0;
let mut orchard_outputs: usize = 0;
let mut ironwood_inputs: usize = 0;
let mut ironwood_outputs: usize = 0;
match source_protocol {
Some(ShieldedPool::Sapling) => sapling_inputs += 1,
Some(ShieldedPool::Orchard) => orchard_inputs += 1,
Some(ShieldedPool::Ironwood) => ironwood_inputs += 1,
None => {}
}
match target_pool {
PoolType::Transparent => transparent_outputs += 1,
PoolType::Shielded(ShieldedPool::Sapling) => sapling_outputs += 1,
PoolType::Shielded(ShieldedPool::Orchard) => orchard_outputs += 1,
PoolType::Shielded(ShieldedPool::Ironwood) => ironwood_outputs += 1,
}
if change {
if orchard_inputs > 0 {
ironwood_outputs += 1;
} else if ironwood_inputs + ironwood_outputs == 0 {
sapling_outputs += 1;
} else {
ironwood_outputs += 1;
}
}
let pad = |inputs: usize, outputs: usize| {
let actions = max(inputs, outputs);
if actions > 0 { max(actions, 2) } else { 0 }
};
let contribution_transparent = max(transparent_outputs, transparent_inputs);
let contribution_sapling = pad(sapling_inputs, sapling_outputs);
let mut contribution_orchard = pad(orchard_inputs, orchard_outputs);
if source_protocol == Some(ShieldedPool::Orchard) && target_pool == PoolType::ORCHARD {
contribution_orchard *= 2;
}
let contribution_ironwood = pad(ironwood_inputs, ironwood_outputs);
let total_fee = MARGINAL_FEE
* max(
contribution_transparent
+ contribution_sapling
+ contribution_orchard
+ contribution_ironwood,
GRACE_ACTIONS,
);
total_fee
.expect("actions expected to be in numerical range")
.into_u64()
}