use fastnum::UD64;
use super::*;
pub const FEE_TIERS: usize = 8;
const DEFAULT_FEE_KEY: u32 = 1021;
const DEFAULT_RWA_FEE_KEY: u32 = 1022;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum FeeScheduleKey {
Default,
RwaDefault,
Custom(types::PerpetualId),
}
impl FeeScheduleKey {
pub fn from_raw(key: U256) -> Self {
match key.to::<u32>() {
DEFAULT_FEE_KEY => Self::Default,
DEFAULT_RWA_FEE_KEY => Self::RwaDefault,
perp_id => Self::Custom(perp_id),
}
}
pub fn to_raw(self) -> U256 {
match self {
Self::Default => U256::from(DEFAULT_FEE_KEY),
Self::RwaDefault => U256::from(DEFAULT_RWA_FEE_KEY),
Self::Custom(perp_id) => U256::from(perp_id),
}
}
}
impl std::fmt::Display for FeeScheduleKey {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Default => write!(f, "default"),
Self::RwaDefault => write!(f, "rwa"),
Self::Custom(perp_id) => write!(f, "custom #{perp_id}"),
}
}
}
#[derive(Clone, Copy)]
pub struct FeeSchedule {
key: FeeScheduleKey,
tiered: bool,
taker_fees: [UD64; FEE_TIERS],
maker_fees: [UD64; FEE_TIERS],
}
impl FeeSchedule {
pub(crate) fn new(
key: FeeScheduleKey,
taker_fees_per_100k: [U256; FEE_TIERS],
maker_fees_per_100k: [U256; FEE_TIERS],
fee_converter: num::Converter,
) -> Self {
Self {
key,
tiered: true,
taker_fees: taker_fees_per_100k.map(|fee| fee_converter.from_unsigned(fee)),
maker_fees: maker_fees_per_100k.map(|fee| fee_converter.from_unsigned(fee)),
}
}
pub(crate) fn flat(key: FeeScheduleKey, taker_fee: UD64, maker_fee: UD64) -> Self {
Self {
key,
tiered: false,
taker_fees: [taker_fee; FEE_TIERS],
maker_fees: [maker_fee; FEE_TIERS],
}
}
pub fn key(&self) -> FeeScheduleKey { self.key }
pub fn is_tiered(&self) -> bool { self.tiered }
pub fn taker_fee(&self, tier: types::FeeTier) -> UD64 {
self.taker_fees
.get(tier as usize)
.copied()
.unwrap_or(self.taker_fees[0])
}
pub fn maker_fee(&self, tier: types::FeeTier) -> UD64 {
self.maker_fees
.get(tier as usize)
.copied()
.unwrap_or(self.maker_fees[0])
}
pub fn base_taker_fee(&self) -> UD64 { self.taker_fees[0] }
pub fn base_maker_fee(&self) -> UD64 { self.maker_fees[0] }
pub fn taker_fees(&self) -> &[UD64; FEE_TIERS] { &self.taker_fees }
pub fn maker_fees(&self) -> &[UD64; FEE_TIERS] { &self.maker_fees }
pub(crate) fn with_key(&self, key: FeeScheduleKey) -> Self { Self { key, ..*self } }
pub(crate) fn with_base_taker_fee(&self, taker_fee: UD64) -> Self {
let mut taker_fees = self.taker_fees;
taker_fees[0] = taker_fee;
Self { taker_fees, ..*self }
}
pub(crate) fn with_base_maker_fee(&self, maker_fee: UD64) -> Self {
let mut maker_fees = self.maker_fees;
maker_fees[0] = maker_fee;
Self { maker_fees, ..*self }
}
}
impl std::fmt::Debug for FeeSchedule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "FeeSchedule {{ key: {}, tiers: [", self.key)?;
for tier in 0..FEE_TIERS {
write!(
f,
"{}{}/{}",
if tier > 0 { " " } else { "" },
self.taker_fees[tier],
self.maker_fees[tier],
)?;
}
write!(f, "] }}")
}
}
#[derive(Clone, Debug)]
pub struct FeeScheduleRegistry {
default: FeeSchedule,
rwa_default: FeeSchedule,
custom: HashMap<types::PerpetualId, FeeSchedule>,
}
impl FeeScheduleRegistry {
pub(crate) fn new(
default: FeeSchedule,
rwa_default: FeeSchedule,
custom: HashMap<types::PerpetualId, FeeSchedule>,
) -> Self {
Self { default, rwa_default, custom }
}
pub fn default_schedule(&self) -> FeeSchedule { self.default }
pub fn rwa_default_schedule(&self) -> FeeSchedule { self.rwa_default }
pub fn custom_schedules(&self) -> &HashMap<types::PerpetualId, FeeSchedule> { &self.custom }
pub fn schedules(&self) -> impl Iterator<Item = FeeSchedule> {
[self.default, self.rwa_default].into_iter().chain(
self.custom
.keys()
.sorted()
.map(|perp_id| self.custom[perp_id]),
)
}
pub fn get(&self, key: FeeScheduleKey) -> Option<FeeSchedule> {
match key {
FeeScheduleKey::Default => Some(self.default),
FeeScheduleKey::RwaDefault => Some(self.rwa_default),
FeeScheduleKey::Custom(perp_id) => self.custom.get(&perp_id).copied(),
}
}
pub(crate) fn set(&mut self, schedule: FeeSchedule) {
match schedule.key() {
FeeScheduleKey::Default => self.default = schedule,
FeeScheduleKey::RwaDefault => self.rwa_default = schedule,
FeeScheduleKey::Custom(perp_id) => {
self.custom.insert(perp_id, schedule);
},
}
}
}
impl std::fmt::Display for FeeSchedule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
write!(f, "{}: ", self.key)?;
for tier in 0..FEE_TIERS {
write!(
f,
"{}{}/{}",
if tier > 0 { " | " } else { "" },
self.taker_fees[tier],
self.maker_fees[tier],
)?;
}
Ok(())
} else {
write!(f, "{} / {} ({})", self.base_taker_fee(), self.base_maker_fee(), self.key)
}
}
}