diff --git a/core/src/instruction.rs b/core/src/instruction.rs index b532192..020af7f 100644 --- a/core/src/instruction.rs +++ b/core/src/instruction.rs @@ -198,4 +198,14 @@ pub enum TipRouterInstruction { first_slot_of_ncn_epoch: Option, }, + #[account(0, name = "restaking_config")] + #[account(1, name = "ncn_config")] + #[account(2, name = "ncn")] + #[account(3, writable, name = "epoch_reward_router")] + #[account(4, writable, name = "destination")] + #[account(5, name = "restaking_program_id")] + DistributeDaoRewards{ + first_slot_of_ncn_epoch: Option, + }, + } diff --git a/program/src/distribute_dao_rewards.rs b/program/src/distribute_dao_rewards.rs new file mode 100644 index 0000000..fd19eb5 --- /dev/null +++ b/program/src/distribute_dao_rewards.rs @@ -0,0 +1,65 @@ +use jito_bytemuck::AccountDeserialize; +use jito_restaking_core::{config::Config, ncn::Ncn}; +use jito_tip_router_core::{ + epoch_reward_router::EpochRewardRouter, error::TipRouterError, loaders::load_ncn_epoch, + ncn_config::NcnConfig, +}; +use solana_program::{ + account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, + program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar, +}; + +/// Initializes a Epoch Reward Router +/// Can be backfilled for previous epochs +pub fn process_distribute_dao_rewards( + program_id: &Pubkey, + accounts: &[AccountInfo], + first_slot_of_ncn_epoch: Option, +) -> ProgramResult { + let [restaking_config, ncn_config, ncn, epoch_reward_router, destination, restaking_program] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if restaking_program.key.ne(&jito_restaking_program::id()) { + msg!("Incorrect restaking program ID"); + return Err(ProgramError::InvalidAccountData); + } + + Config::load(restaking_program.key, restaking_config, false)?; + Ncn::load(restaking_program.key, ncn, false)?; + + let current_slot = Clock::get()?.slot; + let (ncn_epoch, _) = load_ncn_epoch(restaking_config, current_slot, first_slot_of_ncn_epoch)?; + + NcnConfig::load(program_id, ncn.key, ncn_config, false)?; + EpochRewardRouter::load(program_id, ncn.key, ncn_epoch, epoch_reward_router, true)?; + + // Get rewards and update state + let rewards = { + let ncn_config_data = ncn_config.try_borrow_data()?; + let ncn_config_account = NcnConfig::try_from_slice_unchecked(&ncn_config_data)?; + let fee_config = ncn_config_account.fee_config; + + let mut epoch_reward_router_data = epoch_reward_router.try_borrow_mut_data()?; + let epoch_reward_router_account = + EpochRewardRouter::try_from_slice_unchecked_mut(&mut epoch_reward_router_data)?; + + epoch_reward_router_account.distribute_dao_rewards(&fee_config, destination.key)? + }; + + // Send rewards + { + **destination.lamports.borrow_mut() = destination + .lamports() + .checked_add(rewards) + .ok_or(TipRouterError::ArithmeticOverflow)?; + **epoch_reward_router.lamports.borrow_mut() = epoch_reward_router + .lamports() + .checked_sub(rewards) + .ok_or(TipRouterError::ArithmeticOverflow)?; + } + + Ok(()) +} diff --git a/program/src/distribute_rewards.rs b/program/src/distribute_rewards.rs deleted file mode 100644 index 38d71a8..0000000 --- a/program/src/distribute_rewards.rs +++ /dev/null @@ -1,95 +0,0 @@ -use jito_bytemuck::AccountDeserialize; -use jito_restaking_core::{config::Config, ncn::Ncn, operator::Operator}; -use jito_tip_router_core::{ - epoch_reward_router::EpochRewardRouter, - epoch_snapshot::{EpochSnapshot, OperatorSnapshot}, - loaders::load_ncn_epoch, - ncn_config::NcnConfig, - operator_epoch_reward_router::OperatorEpochRewardRouter, - rewards::RewardType, -}; -use solana_program::{ - account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, - program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar, -}; - -/// Initializes a Epoch Reward Router -/// Can be backfilled for previous epochs -pub fn process_distribute_rewards( - program_id: &Pubkey, - accounts: &[AccountInfo], - reward_type: u8, - first_slot_of_ncn_epoch: Option, -) -> ProgramResult { - let [restaking_config, ncn_config, ncn, operator, epoch_reward_router, operator_epoch_reward_router, destination, restaking_program] = - accounts - else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - - if restaking_program.key.ne(&jito_restaking_program::id()) { - msg!("Incorrect restaking program ID"); - return Err(ProgramError::InvalidAccountData); - } - - Config::load(restaking_program.key, restaking_config, false)?; - Ncn::load(restaking_program.key, ncn, false)?; - Operator::load(restaking_program.key, operator, false)?; - - let current_slot = Clock::get()?.slot; - let (ncn_epoch, _) = load_ncn_epoch(restaking_config, current_slot, first_slot_of_ncn_epoch)?; - - NcnConfig::load(program_id, ncn.key, ncn_config, false)?; - EpochRewardRouter::load(program_id, ncn.key, ncn_epoch, epoch_reward_router, true)?; - OperatorEpochRewardRouter::load( - program_id, - operator.key, - ncn.key, - ncn_epoch, - operator_epoch_reward_router, - true, - )?; - - let reward_type = RewardType::try_from(reward_type)?; - - let rewards = match reward_type { - RewardType::DAO => { - process_epoch_reward(&epoch_reward_router)?; - } - RewardType::NCN => { - process_epoch_reward_pool(&epoch_reward_router)?; - } - RewardType::OperatorReward => { - process_operator_epoch_reward_pool(&operator_epoch_reward_router)?; - } - RewardType::Vault => { - process_epoch_reward_pool(&epoch_reward_router)?; - } - }; - - // Send rewards - {} - - // let operator_snapshot = { - // let operator_snapshot_data = operator_snapshot.try_borrow_data()?; - // let operator_snapshot_account = - // OperatorSnapshot::try_from_slice_unchecked(&operator_snapshot_data)?; - - // *operator_snapshot_account - // }; - - // let account_balance = **operator_epoch_reward_router.try_borrow_lamports()?; - - // let mut operator_epoch_reward_router_data = - // operator_epoch_reward_router.try_borrow_mut_data()?; - // let operator_epoch_reward_router_account = - // OperatorEpochRewardRouter::try_from_slice_unchecked_mut( - // &mut operator_epoch_reward_router_data, - // )?; - - // operator_epoch_reward_router_account.process_incoming_rewards(account_balance)?; - - // operator_epoch_reward_router_account.process_reward_pool(&operator_snapshot)?; - - Ok(()) -} diff --git a/program/src/lib.rs b/program/src/lib.rs index a54af29..dec2414 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -1,5 +1,5 @@ mod admin_update_weight_table; -mod distribute_rewards; +mod distribute_dao_rewards; mod initialize_epoch_reward_router; mod initialize_epoch_snapshot; mod initialize_ncn_config; @@ -28,6 +28,7 @@ use solana_security_txt::security_txt; use crate::{ admin_update_weight_table::process_admin_update_weight_table, + distribute_dao_rewards::process_distribute_dao_rewards, initialize_epoch_reward_router::process_initialize_epoch_reward_router, initialize_epoch_snapshot::process_initialize_epoch_snapshot, initialize_ncn_config::process_initialize_ncn_config, @@ -193,5 +194,11 @@ pub fn process_instruction( first_slot_of_ncn_epoch, ) } + TipRouterInstruction::DistributeDaoRewards { + first_slot_of_ncn_epoch, + } => { + msg!("Instruction: DistributeDAORewards"); + process_distribute_dao_rewards(program_id, accounts, first_slot_of_ncn_epoch) + } } }