use anchor_lang::prelude::*;
pub trait CommissionCalculator {
fn calculate_commission_multiplier(&self, time_since_ready: i64) -> f64;
fn calculate_effective_commission(&self, time_since_ready: i64) -> u64;
fn calculate_executor_fee(&self, effective_commission: u64) -> u64;
fn calculate_core_team_fee(&self, effective_commission: u64) -> u64;
}
#[derive(Debug)]
pub struct PaymentDetails {
pub fee_payer_reimbursement: u64,
pub executor_commission: u64,
pub core_team_fee: u64,
}
pub trait PaymentProcessor {
fn calculate_payments(
&self,
time_since_ready: i64,
balance_change: i64,
forgo_commission: bool,
) -> PaymentDetails;
fn should_pay(&self, balance_change: i64) -> bool {
balance_change <= 0 }
fn calculate_reimbursement(&self, balance_change: i64) -> u64 {
if balance_change < 0 {
balance_change.unsigned_abs()
} else if balance_change > 0 {
0 } else {
5000u64 }
}
}
#[account]
#[derive(Debug, InitSpace)]
pub struct ThreadConfig {
pub version: u64,
pub bump: u8,
pub admin: Pubkey,
pub paused: bool,
pub commission_fee: u64,
pub executor_fee_bps: u64,
pub core_team_bps: u64,
pub grace_period_seconds: i64,
pub fee_decay_seconds: i64,
}
impl ThreadConfig {
pub fn pubkey() -> Pubkey {
Pubkey::find_program_address(&[crate::SEED_CONFIG], &crate::ID).0
}
pub fn space() -> usize {
8 + Self::INIT_SPACE
}
}
impl CommissionCalculator for ThreadConfig {
fn calculate_commission_multiplier(&self, time_since_ready: i64) -> f64 {
if time_since_ready <= self.grace_period_seconds {
1.0
} else if time_since_ready <= self.grace_period_seconds + self.fee_decay_seconds {
let time_into_decay = (time_since_ready - self.grace_period_seconds) as f64;
let decay_progress = time_into_decay / self.fee_decay_seconds as f64;
1.0 - decay_progress
} else {
0.0
}
}
fn calculate_effective_commission(&self, time_since_ready: i64) -> u64 {
let multiplier = self.calculate_commission_multiplier(time_since_ready);
(self.commission_fee as f64 * multiplier) as u64
}
fn calculate_executor_fee(&self, effective_commission: u64) -> u64 {
(effective_commission * self.executor_fee_bps) / 10_000
}
fn calculate_core_team_fee(&self, effective_commission: u64) -> u64 {
(effective_commission * self.core_team_bps) / 10_000
}
}
impl PaymentProcessor for ThreadConfig {
fn calculate_payments(
&self,
time_since_ready: i64,
balance_change: i64,
forgo_commission: bool,
) -> PaymentDetails {
let effective_commission = self.calculate_effective_commission(time_since_ready);
let (fee_payer_reimbursement, executor_commission) = if self.should_pay(balance_change) {
let reimbursement = self.calculate_reimbursement(balance_change);
let commission = if !forgo_commission {
self.calculate_executor_fee(effective_commission)
} else {
0
};
(reimbursement, commission)
} else {
(0, 0)
};
let core_team_fee = self.calculate_core_team_fee(effective_commission);
PaymentDetails {
fee_payer_reimbursement,
executor_commission,
core_team_fee,
}
}
}