Skip to content

Commit

Permalink
Pod for Fees
Browse files Browse the repository at this point in the history
  • Loading branch information
ebatsell committed Nov 8, 2024
1 parent a16f795 commit a4b7aa9
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 65 deletions.
4 changes: 0 additions & 4 deletions clients/js/jito_tip_router/accounts/ncnConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,3 @@ export async function fetchAllMaybeNcnConfig(
const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config);
return maybeAccounts.map((maybeAccount) => decodeNcnConfig(maybeAccount));
}

export function getNcnConfigSize(): number {
return 352;
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ pub struct NcnConfig {
}

impl NcnConfig {
pub const LEN: usize = 352;

#[inline(always)]
pub fn from_bytes(data: &[u8]) -> Result<Self, std::io::Error> {
let mut data = data;
Expand Down
145 changes: 90 additions & 55 deletions core/src/fees.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use bytemuck::{Pod, Zeroable};
use jito_bytemuck::types::PodU64;
use shank::ShankType;
use solana_program::pubkey::Pubkey;

Expand All @@ -14,7 +15,7 @@ pub struct Fees {
}

impl Fees {
pub const fn new(
pub fn new(
wallet: Pubkey,
dao_fee_share_bps: u64,
ncn_fee_share_bps: u64,
Expand All @@ -34,25 +35,25 @@ impl Fees {
}
}

const fn current_fee(&self, current_epoch: u64) -> &Fee {
fn current_fee(&self, current_epoch: u64) -> &Fee {
// If either fee is not yet active, return the other one
if self.fee_1.activation_epoch > current_epoch {
if self.fee_1.activation_epoch() > current_epoch {
return &self.fee_2;
}
if self.fee_2.activation_epoch > current_epoch {
if self.fee_2.activation_epoch() > current_epoch {
return &self.fee_1;
}

// Otherwise return the one with higher activation epoch
if self.fee_1.activation_epoch >= self.fee_2.activation_epoch {
if self.fee_1.activation_epoch() >= self.fee_2.activation_epoch() {
&self.fee_1
} else {
&self.fee_2
}
}

pub const fn block_engine_fee(&self, current_epoch: u64) -> u64 {
self.current_fee(current_epoch).block_engine_fee_bps
pub fn block_engine_fee(&self, current_epoch: u64) -> u64 {
self.current_fee(current_epoch).block_engine_fee_bps()
}

/// Calculate fee as a portion of remaining BPS after block engine fee
Expand All @@ -61,9 +62,9 @@ impl Fees {
pub fn dao_fee(&self, current_epoch: u64) -> Result<u64, TipRouterError> {
let fee = self.current_fee(current_epoch);
let remaining_bps = MAX_FEE_BPS
.checked_sub(fee.block_engine_fee_bps)
.checked_sub(fee.block_engine_fee_bps())
.ok_or(TipRouterError::ArithmeticOverflow)?;
fee.dao_share_bps
fee.dao_share_bps()
.checked_mul(MAX_FEE_BPS)
.and_then(|x| x.checked_div(remaining_bps))
.ok_or(TipRouterError::ArithmeticOverflow)
Expand All @@ -75,29 +76,29 @@ impl Fees {
pub fn ncn_fee(&self, current_epoch: u64) -> Result<u64, TipRouterError> {
let fee = self.current_fee(current_epoch);
let remaining_bps = MAX_FEE_BPS
.checked_sub(fee.block_engine_fee_bps)
.checked_sub(fee.block_engine_fee_bps())
.ok_or(TipRouterError::ArithmeticOverflow)?;
fee.ncn_share_bps
fee.ncn_share_bps()
.checked_mul(MAX_FEE_BPS)
.and_then(|x| x.checked_div(remaining_bps))
.ok_or(TipRouterError::ArithmeticOverflow)
}

pub const fn fee_wallet(&self, current_epoch: u64) -> Pubkey {
pub fn fee_wallet(&self, current_epoch: u64) -> Pubkey {
self.current_fee(current_epoch).wallet
}

fn get_updatable_fee_mut(&mut self, current_epoch: u64) -> &mut Fee {
// If either fee is scheduled for next epoch, return that one
if self.fee_1.activation_epoch > current_epoch {
if self.fee_1.activation_epoch() > current_epoch {
return &mut self.fee_1;
}
if self.fee_2.activation_epoch > current_epoch {
if self.fee_2.activation_epoch() > current_epoch {
return &mut self.fee_2;
}

// Otherwise return the one with lower activation epoch
if self.fee_1.activation_epoch <= self.fee_2.activation_epoch {
if self.fee_1.activation_epoch() <= self.fee_2.activation_epoch() {
&mut self.fee_1
} else {
&mut self.fee_2
Expand All @@ -120,26 +121,28 @@ impl Fees {
if new_dao_fee_bps > MAX_FEE_BPS {
return Err(TipRouterError::FeeCapExceeded);
}
new_fees.dao_share_bps = new_dao_fee_bps;
new_fees.set_dao_share_bps(new_dao_fee_bps);
}
if let Some(new_ncn_fee_bps) = new_ncn_fee_bps {
if new_ncn_fee_bps > MAX_FEE_BPS {
return Err(TipRouterError::FeeCapExceeded);
}
new_fees.ncn_share_bps = new_ncn_fee_bps;
new_fees.set_ncn_share_bps(new_ncn_fee_bps);
}
if let Some(new_block_engine_fee_bps) = new_block_engine_fee_bps {
if new_block_engine_fee_bps > MAX_FEE_BPS {
return Err(TipRouterError::FeeCapExceeded);
}
new_fees.block_engine_fee_bps = new_block_engine_fee_bps;
new_fees.set_block_engine_fee_bps(new_block_engine_fee_bps);
}
if let Some(new_wallet) = new_wallet {
new_fees.wallet = new_wallet;
}
new_fees.activation_epoch = current_epoch
.checked_add(1)
.ok_or(TipRouterError::ArithmeticOverflow)?;
new_fees.set_activation_epoch(
current_epoch
.checked_add(1)
.ok_or(TipRouterError::ArithmeticOverflow)?,
);
Ok(())
}
}
Expand All @@ -148,14 +151,14 @@ impl Fees {
#[repr(C)]
pub struct Fee {
wallet: Pubkey,
dao_share_bps: u64,
ncn_share_bps: u64,
block_engine_fee_bps: u64,
activation_epoch: u64,
dao_share_bps: PodU64,
ncn_share_bps: PodU64,
block_engine_fee_bps: PodU64,
activation_epoch: PodU64,
}

impl Fee {
pub const fn new(
pub fn new(
wallet: Pubkey,
dao_share_bps: u64,
ncn_share_bps: u64,
Expand All @@ -164,12 +167,44 @@ impl Fee {
) -> Self {
Self {
wallet,
dao_share_bps,
ncn_share_bps,
block_engine_fee_bps,
activation_epoch: epoch,
dao_share_bps: PodU64::from(dao_share_bps),
ncn_share_bps: PodU64::from(ncn_share_bps),
block_engine_fee_bps: PodU64::from(block_engine_fee_bps),
activation_epoch: PodU64::from(epoch),
}
}

pub fn dao_share_bps(&self) -> u64 {
self.dao_share_bps.into()
}

pub fn ncn_share_bps(&self) -> u64 {
self.ncn_share_bps.into()
}

pub fn block_engine_fee_bps(&self) -> u64 {
self.block_engine_fee_bps.into()
}

pub fn activation_epoch(&self) -> u64 {
self.activation_epoch.into()
}

fn set_dao_share_bps(&mut self, value: u64) {
self.dao_share_bps = PodU64::from(value);
}

fn set_ncn_share_bps(&mut self, value: u64) {
self.ncn_share_bps = PodU64::from(value);
}

fn set_block_engine_fee_bps(&mut self, value: u64) {
self.block_engine_fee_bps = PodU64::from(value);
}

fn set_activation_epoch(&mut self, value: u64) {
self.activation_epoch = PodU64::from(value);
}
}

#[cfg(test)]
Expand All @@ -185,26 +220,26 @@ mod tests {

fees.set_new_fees(Some(400), None, None, Some(new_wallet), 10)
.unwrap();
assert_eq!(fees.fee_1.dao_share_bps, 400);
assert_eq!(fees.fee_1.dao_share_bps(), 400);
assert_eq!(fees.fee_1.wallet, new_wallet);
assert_eq!(fees.fee_1.activation_epoch, 11);
assert_eq!(fees.fee_1.activation_epoch(), 11);
}

#[test]
fn test_update_fees_no_changes() {
let original = Fee::new(Pubkey::new_unique(), 100, 200, 300, 5);
let mut fees = Fees::new(Pubkey::new_unique(), 100, 200, 300, 5);
fees.fee_1 = original.clone();
fees.fee_1 = original;

fees.set_new_fees(None, None, None, None, 10).unwrap();
assert_eq!(fees.fee_1.dao_share_bps, original.dao_share_bps);
assert_eq!(fees.fee_1.ncn_share_bps, original.ncn_share_bps);
assert_eq!(fees.fee_1.dao_share_bps(), original.dao_share_bps());
assert_eq!(fees.fee_1.ncn_share_bps(), original.ncn_share_bps());
assert_eq!(
fees.fee_1.block_engine_fee_bps,
original.block_engine_fee_bps
fees.fee_1.block_engine_fee_bps(),
original.block_engine_fee_bps()
);
assert_eq!(fees.fee_1.wallet, original.wallet);
assert_eq!(fees.fee_1.activation_epoch, 11);
assert_eq!(fees.fee_1.activation_epoch(), 11);
}

#[test]
Expand All @@ -228,39 +263,39 @@ mod tests {
fn test_current_fee() {
let mut fees = Fees::new(Pubkey::new_unique(), 100, 200, 300, 5);

assert_eq!(fees.current_fee(5).activation_epoch, 5);
assert_eq!(fees.current_fee(5).activation_epoch(), 5);

fees.fee_1.activation_epoch = 10;
fees.fee_1.set_activation_epoch(10);

assert_eq!(fees.current_fee(5).activation_epoch, 5);
assert_eq!(fees.current_fee(10).activation_epoch, 10);
assert_eq!(fees.current_fee(5).activation_epoch(), 5);
assert_eq!(fees.current_fee(10).activation_epoch(), 10);

fees.fee_2.activation_epoch = 15;
fees.fee_2.set_activation_epoch(15);

assert_eq!(fees.current_fee(12).activation_epoch, 10);
assert_eq!(fees.current_fee(15).activation_epoch, 15);
assert_eq!(fees.current_fee(12).activation_epoch(), 10);
assert_eq!(fees.current_fee(15).activation_epoch(), 15);
}

#[test]
fn test_get_updatable_fee_mut() {
let mut fees = Fees::new(Pubkey::new_unique(), 100, 200, 300, 5);

let fee = fees.get_updatable_fee_mut(10);
fee.dao_share_bps = 400;
fee.activation_epoch = 11;
fee.set_dao_share_bps(400);
fee.set_activation_epoch(11);

assert_eq!(fees.fee_1.dao_share_bps, 400);
assert_eq!(fees.fee_1.activation_epoch, 11);
assert_eq!(fees.fee_1.dao_share_bps(), 400);
assert_eq!(fees.fee_1.activation_epoch(), 11);

fees.fee_2.activation_epoch = 13;
fees.fee_2.set_activation_epoch(13);

let fee = fees.get_updatable_fee_mut(12);
fee.dao_share_bps = 500;
fee.activation_epoch = 13;
fee.set_dao_share_bps(500);
fee.set_activation_epoch(13);

assert_eq!(fees.fee_2.dao_share_bps, 500);
assert_eq!(fees.fee_2.activation_epoch, 13);
assert_eq!(fees.fee_2.dao_share_bps(), 500);
assert_eq!(fees.fee_2.activation_epoch(), 13);

assert_eq!(fees.get_updatable_fee_mut(u64::MAX).activation_epoch, 11);
assert_eq!(fees.get_updatable_fee_mut(u64::MAX).activation_epoch(), 11);
}
}
16 changes: 12 additions & 4 deletions idl/jito_tip_router.json
Original file line number Diff line number Diff line change
Expand Up @@ -385,19 +385,27 @@
},
{
"name": "daoShareBps",
"type": "u64"
"type": {
"defined": "PodU64"
}
},
{
"name": "ncnShareBps",
"type": "u64"
"type": {
"defined": "PodU64"
}
},
{
"name": "blockEngineFeeBps",
"type": "u64"
"type": {
"defined": "PodU64"
}
},
{
"name": "activationEpoch",
"type": "u64"
"type": {
"defined": "PodU64"
}
}
]
}
Expand Down

0 comments on commit a4b7aa9

Please sign in to comment.