From 2a135cee8d21b4406b641f5f6d9b52d91e40a160 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Fri, 8 Nov 2024 11:27:16 -0700 Subject: [PATCH 01/28] starting epoch snapshot --- core/src/constants.rs | 1 + core/src/epoch_snapshot.rs | 350 +++++++++++++++++++++++++++ core/src/fees.rs | 2 +- core/src/lib.rs | 4 +- program/src/initialize_ncn_config.rs | 4 +- 5 files changed, 357 insertions(+), 4 deletions(-) create mode 100644 core/src/constants.rs create mode 100644 core/src/epoch_snapshot.rs diff --git a/core/src/constants.rs b/core/src/constants.rs new file mode 100644 index 0000000..4868349 --- /dev/null +++ b/core/src/constants.rs @@ -0,0 +1 @@ +pub const MAX_FEE_BPS: u64 = 10_000; diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs new file mode 100644 index 0000000..8ec499a --- /dev/null +++ b/core/src/epoch_snapshot.rs @@ -0,0 +1,350 @@ +use std::collections::HashSet; + +use bytemuck::{Pod, Zeroable}; +use jito_bytemuck::{types::PodU64, AccountDeserialize, Discriminator}; +use shank::{ShankAccount, ShankType}; +use solana_program::{account_info::AccountInfo, msg, program_error::ProgramError, pubkey::Pubkey}; + +use crate::{discriminators::Discriminators, error::TipRouterError, weight_entry::WeightEntry}; + +// PDA'd ["WEIGHT_TABLE", NCN, NCN_EPOCH_SLOT] +#[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] +#[repr(C)] +pub struct WeightTable { + /// The NCN on-chain program is the signer to create and update this account, + /// this pushes the responsibility of managing the account to the NCN program. + ncn: Pubkey, + + /// The NCN epoch for which the weight table is valid + ncn_epoch: PodU64, + + /// Slot weight table was created + slot_created: PodU64, + + /// Bump seed for the PDA + bump: u8, + + /// Reserved space + reserved: [u8; 128], + + /// The weight table + table: [WeightEntry; 32], +} + +impl Discriminator for WeightTable { + const DISCRIMINATOR: u8 = Discriminators::WeightTable as u8; +} + +impl WeightTable { + pub const MAX_TABLE_ENTRIES: usize = 32; + + pub fn new(ncn: Pubkey, ncn_epoch: u64, slot_created: u64, bump: u8) -> Self { + Self { + ncn, + ncn_epoch: PodU64::from(ncn_epoch), + slot_created: PodU64::from(slot_created), + bump, + reserved: [0; 128], + table: [WeightEntry::default(); Self::MAX_TABLE_ENTRIES], + } + } + + pub fn seeds(ncn: &Pubkey, ncn_epoch: u64) -> Vec> { + Vec::from_iter( + [ + b"WEIGHT_TABLE".to_vec(), + ncn.to_bytes().to_vec(), + ncn_epoch.to_le_bytes().to_vec(), + ] + .iter() + .cloned(), + ) + } + + pub fn find_program_address( + program_id: &Pubkey, + ncn: &Pubkey, + ncn_epoch: u64, + ) -> (Pubkey, u8, Vec>) { + let seeds = Self::seeds(ncn, ncn_epoch); + let seeds_iter: Vec<_> = seeds.iter().map(|s| s.as_slice()).collect(); + let (pda, bump) = Pubkey::find_program_address(&seeds_iter, program_id); + (pda, bump, seeds) + } + + pub fn initalize_weight_table( + &mut self, + config_supported_mints: &[Pubkey], + ) -> Result<(), TipRouterError> { + if self.initialized() { + return Err(TipRouterError::WeightTableAlreadyInitialized); + } + + // Check for empty vector + if config_supported_mints.is_empty() { + return Err(TipRouterError::NoMintsInTable); + } + + // Check if vector exceeds maximum allowed entries + if config_supported_mints.len() > Self::MAX_TABLE_ENTRIES { + return Err(TipRouterError::TooManyMintsForTable); + } + + // Check for duplicates using nested iterators + let unique_mints: HashSet<_> = config_supported_mints.iter().collect(); + + if unique_mints.len() != config_supported_mints.len() { + return Err(TipRouterError::DuplicateMintsInTable); + } + + // Set table using iterator + self.table + .iter_mut() + .zip(config_supported_mints.iter()) + .for_each(|(entry, &mint)| { + *entry = WeightEntry::new(mint); + }); + + self.check_initialized()?; + + Ok(()) + } + + pub fn set_weight( + &mut self, + mint: &Pubkey, + weight: u128, + current_slot: u64, + ) -> Result<(), TipRouterError> { + self.table + .iter_mut() + .find(|entry| entry.mint() == *mint) + .map_or(Err(TipRouterError::InvalidMintForWeightTable), |entry| { + entry.set_weight(weight, current_slot); + Ok(()) + }) + } + + pub fn get_weight(&self, mint: &Pubkey) -> Result { + self.table + .iter() + .find(|entry| entry.mint() == *mint) + .map_or(Err(TipRouterError::InvalidMintForWeightTable), |entry| { + Ok(entry.weight()) + }) + } + + pub fn get_mints(&self) -> Vec { + self.table + .iter() + .filter(|entry| !entry.is_empty()) + .map(|entry| entry.mint()) + .collect() + } + + pub fn find_weight(&self, mint: &Pubkey) -> Option { + self.table + .iter() + .find(|entry| entry.mint() == *mint) + .map(|entry| entry.weight()) + } + + pub fn mint_count(&self) -> usize { + self.table.iter().filter(|entry| !entry.is_empty()).count() + } + + pub fn weight_count(&self) -> usize { + self.table.iter().filter(|entry| !entry.is_set()).count() + } + + pub const fn ncn(&self) -> Pubkey { + self.ncn + } + + pub fn ncn_epoch(&self) -> u64 { + self.ncn_epoch.into() + } + + pub fn slot_created(&self) -> u64 { + self.slot_created.into() + } + + pub fn initialized(&self) -> bool { + self.mint_count() > 0 + } + + pub fn finalized(&self) -> bool { + self.initialized() && self.mint_count() == self.weight_count() + } + + pub fn check_initialized(&self) -> Result<(), TipRouterError> { + if !self.initialized() { + return Err(TipRouterError::NoMintsInTable); + } + Ok(()) + } + + pub fn load( + program_id: &Pubkey, + weight_table: &AccountInfo, + ncn: &AccountInfo, + ncn_epoch: u64, + expect_writable: bool, + ) -> Result<(), ProgramError> { + if weight_table.owner.ne(program_id) { + msg!("Weight table account is not owned by the program"); + return Err(ProgramError::InvalidAccountOwner); + } + if weight_table.data_is_empty() { + msg!("Weight table account is empty"); + return Err(ProgramError::InvalidAccountData); + } + if expect_writable && !weight_table.is_writable { + msg!("Weight table account is not writable"); + return Err(ProgramError::InvalidAccountData); + } + if weight_table.data.borrow()[0].ne(&Self::DISCRIMINATOR) { + msg!("Weight table account has an incorrect discriminator"); + return Err(ProgramError::InvalidAccountData); + } + let expected_pubkey = Self::find_program_address(program_id, ncn.key, ncn_epoch).0; + if weight_table.key.ne(&expected_pubkey) { + msg!("Weight table incorrect PDA"); + return Err(ProgramError::InvalidAccountData); + } + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use solana_program::pubkey::Pubkey; + + use super::*; + + fn get_test_pubkeys(count: usize) -> Vec { + (0..count).map(|_| Pubkey::new_unique()).collect() + } + + #[test] + fn test_initialize_table_success() { + let ncn = Pubkey::new_unique(); + let mut table = WeightTable::new(ncn, 0, 0, 0); + assert_eq!(table.mint_count(), 0); + + let mints = get_test_pubkeys(2); + table.initalize_weight_table(&mints).unwrap(); + assert_eq!(table.mint_count(), 2); + } + + #[test] + fn test_initialize_table_too_many() { + let ncn = Pubkey::new_unique(); + let mut table = WeightTable::new(ncn, 0, 0, 0); + let many_mints = get_test_pubkeys(WeightTable::MAX_TABLE_ENTRIES + 1); + assert_eq!( + table.initalize_weight_table(&many_mints), + Err(TipRouterError::TooManyMintsForTable) + ); + } + + #[test] + fn test_initialize_table_max() { + let ncn = Pubkey::new_unique(); + let mut table = WeightTable::new(ncn, 0, 0, 0); + let max_mints = get_test_pubkeys(WeightTable::MAX_TABLE_ENTRIES); + table.initalize_weight_table(&max_mints).unwrap(); + assert_eq!(table.mint_count(), WeightTable::MAX_TABLE_ENTRIES); + } + + #[test] + fn test_initialize_table_reinitialize() { + let ncn = Pubkey::new_unique(); + let mut table = WeightTable::new(ncn, 0, 0, 0); + let first_mints = get_test_pubkeys(2); + table.initalize_weight_table(&first_mints).unwrap(); + let second_mints = get_test_pubkeys(3); + + assert_eq!( + table.initalize_weight_table(&second_mints), + Err(TipRouterError::WeightTableAlreadyInitialized) + ); + } + + #[test] + fn test_set_weight_success() { + let ncn = Pubkey::new_unique(); + let mut table = WeightTable::new(ncn, 0, 0, 0); + let mints = get_test_pubkeys(2); + let mint = mints[0]; + + table.initalize_weight_table(&mints).unwrap(); + + table.set_weight(&mint, 100, 1).unwrap(); + assert_eq!(table.get_weight(&mint).unwrap(), 100); + } + + #[test] + fn test_set_weight_invalid_mint() { + let ncn = Pubkey::new_unique(); + let mut table = WeightTable::new(ncn, 0, 0, 0); + let mints = get_test_pubkeys(2); + + table.initalize_weight_table(&mints).unwrap(); + + let invalid_mint = Pubkey::new_unique(); + assert_eq!( + table.set_weight(&invalid_mint, 100, 1), + Err(TipRouterError::InvalidMintForWeightTable) + ); + } + + #[test] + fn test_set_weight_update_existing() { + let ncn = Pubkey::new_unique(); + let mut table = WeightTable::new(ncn, 0, 0, 0); + let mints = get_test_pubkeys(2); + let mint = mints[0]; + + table.initalize_weight_table(&mints).unwrap(); + + table.set_weight(&mint, 100, 1).unwrap(); + assert_eq!(table.get_weight(&mint).unwrap(), 100); + + table.set_weight(&mint, 200, 2).unwrap(); + assert_eq!(table.get_weight(&mint).unwrap(), 200); + } + + #[test] + fn test_set_weight_multiple_mints() { + let ncn = Pubkey::new_unique(); + let mut table = WeightTable::new(ncn, 0, 0, 0); + let mints = get_test_pubkeys(2); + let mint1 = mints[0]; + let mint2 = mints[1]; + + table.initalize_weight_table(&mints).unwrap(); + + table.set_weight(&mint1, 100, 1).unwrap(); + table.set_weight(&mint2, 200, 1).unwrap(); + + assert_eq!(table.get_weight(&mint1).unwrap(), 100); + assert_eq!(table.get_weight(&mint2).unwrap(), 200); + } + + #[test] + fn test_set_weight_different_slots() { + let ncn = Pubkey::new_unique(); + let mut table = WeightTable::new(ncn, 0, 0, 0); + let mints = get_test_pubkeys(2); + let mint = mints[0]; + + table.initalize_weight_table(&mints).unwrap(); + + table.set_weight(&mint, 100, 1).unwrap(); + assert_eq!(table.get_weight(&mint).unwrap(), 100); + + table.set_weight(&mint, 200, 5).unwrap(); + assert_eq!(table.get_weight(&mint).unwrap(), 200); + } +} diff --git a/core/src/fees.rs b/core/src/fees.rs index 6e7c901..2571622 100644 --- a/core/src/fees.rs +++ b/core/src/fees.rs @@ -3,7 +3,7 @@ use jito_bytemuck::types::PodU64; use shank::ShankType; use solana_program::pubkey::Pubkey; -use crate::{error::TipRouterError, MAX_FEE_BPS}; +use crate::{constants::MAX_FEE_BPS, error::TipRouterError}; /// Fee account. Allows for fee updates to take place in a future epoch without requiring an update. /// This is important so all operators calculate the same Merkle root regardless of when fee changes take place. diff --git a/core/src/lib.rs b/core/src/lib.rs index a75de93..f90a556 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,9 +1,9 @@ +pub mod constants; pub mod discriminators; +pub mod epoch_snapshot; pub mod error; pub mod fees; pub mod instruction; pub mod ncn_config; pub mod weight_entry; pub mod weight_table; - -pub const MAX_FEE_BPS: u64 = 10_000; diff --git a/program/src/initialize_ncn_config.rs b/program/src/initialize_ncn_config.rs index 853d816..94ba7d8 100644 --- a/program/src/initialize_ncn_config.rs +++ b/program/src/initialize_ncn_config.rs @@ -4,7 +4,9 @@ use jito_jsm_core::{ loader::{load_signer, load_system_account, load_system_program}, }; use jito_restaking_core::{config::Config, ncn::Ncn}; -use jito_tip_router_core::{error::TipRouterError, fees::Fees, ncn_config::NcnConfig, MAX_FEE_BPS}; +use jito_tip_router_core::{ + constants::MAX_FEE_BPS, error::TipRouterError, fees::Fees, ncn_config::NcnConfig, +}; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, From cf4c10de33b9ca2f49e4805eef873df21242dab1 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Fri, 8 Nov 2024 15:37:35 -0700 Subject: [PATCH 02/28] more thoughts --- core/src/constants.rs | 2 + core/src/discriminators.rs | 4 +- core/src/epoch_snapshot.rs | 366 +++++-------------------------------- core/src/ncn_config.rs | 2 +- 4 files changed, 55 insertions(+), 319 deletions(-) diff --git a/core/src/constants.rs b/core/src/constants.rs index 4868349..01586c4 100644 --- a/core/src/constants.rs +++ b/core/src/constants.rs @@ -1 +1,3 @@ pub const MAX_FEE_BPS: u64 = 10_000; +pub const MAX_OPERATORS: usize = 256; +pub const MAX_VAULT_OPERATOR_DELEGATIONS: usize = 64; diff --git a/core/src/discriminators.rs b/core/src/discriminators.rs index 18f0d31..7df10f6 100644 --- a/core/src/discriminators.rs +++ b/core/src/discriminators.rs @@ -1,5 +1,7 @@ #[repr(u8)] pub enum Discriminators { - Config = 1, + NCNConfig = 1, WeightTable = 2, + EpochSnapshot = 3, + OperatorSnapshot = 4, } diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index 8ec499a..7de3e24 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -1,24 +1,26 @@ -use std::collections::HashSet; - use bytemuck::{Pod, Zeroable}; -use jito_bytemuck::{types::PodU64, AccountDeserialize, Discriminator}; +use jito_bytemuck::{ + types::{PodU128, PodU16, PodU64}, + AccountDeserialize, Discriminator, +}; +use jito_vault_core::delegation_state::DelegationState; use shank::{ShankAccount, ShankType}; -use solana_program::{account_info::AccountInfo, msg, program_error::ProgramError, pubkey::Pubkey}; +use solana_program::pubkey::Pubkey; -use crate::{discriminators::Discriminators, error::TipRouterError, weight_entry::WeightEntry}; +use crate::{discriminators::Discriminators, fees::Fees}; -// PDA'd ["WEIGHT_TABLE", NCN, NCN_EPOCH_SLOT] +// PDA'd ["EPOCH_SNAPSHOT", NCN, NCN_EPOCH_SLOT] #[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] #[repr(C)] -pub struct WeightTable { +pub struct EpochSnapshot { /// The NCN on-chain program is the signer to create and update this account, /// this pushes the responsibility of managing the account to the NCN program. ncn: Pubkey, - /// The NCN epoch for which the weight table is valid + /// The NCN epoch for which the Epoch snapshot is valid ncn_epoch: PodU64, - /// Slot weight table was created + /// Slot Epoch snapshot was created slot_created: PodU64, /// Bump seed for the PDA @@ -27,324 +29,54 @@ pub struct WeightTable { /// Reserved space reserved: [u8; 128], - /// The weight table - table: [WeightEntry; 32], -} - -impl Discriminator for WeightTable { - const DISCRIMINATOR: u8 = Discriminators::WeightTable as u8; -} - -impl WeightTable { - pub const MAX_TABLE_ENTRIES: usize = 32; - - pub fn new(ncn: Pubkey, ncn_epoch: u64, slot_created: u64, bump: u8) -> Self { - Self { - ncn, - ncn_epoch: PodU64::from(ncn_epoch), - slot_created: PodU64::from(slot_created), - bump, - reserved: [0; 128], - table: [WeightEntry::default(); Self::MAX_TABLE_ENTRIES], - } - } - - pub fn seeds(ncn: &Pubkey, ncn_epoch: u64) -> Vec> { - Vec::from_iter( - [ - b"WEIGHT_TABLE".to_vec(), - ncn.to_bytes().to_vec(), - ncn_epoch.to_le_bytes().to_vec(), - ] - .iter() - .cloned(), - ) - } - - pub fn find_program_address( - program_id: &Pubkey, - ncn: &Pubkey, - ncn_epoch: u64, - ) -> (Pubkey, u8, Vec>) { - let seeds = Self::seeds(ncn, ncn_epoch); - let seeds_iter: Vec<_> = seeds.iter().map(|s| s.as_slice()).collect(); - let (pda, bump) = Pubkey::find_program_address(&seeds_iter, program_id); - (pda, bump, seeds) - } - - pub fn initalize_weight_table( - &mut self, - config_supported_mints: &[Pubkey], - ) -> Result<(), TipRouterError> { - if self.initialized() { - return Err(TipRouterError::WeightTableAlreadyInitialized); - } - - // Check for empty vector - if config_supported_mints.is_empty() { - return Err(TipRouterError::NoMintsInTable); - } - - // Check if vector exceeds maximum allowed entries - if config_supported_mints.len() > Self::MAX_TABLE_ENTRIES { - return Err(TipRouterError::TooManyMintsForTable); - } - - // Check for duplicates using nested iterators - let unique_mints: HashSet<_> = config_supported_mints.iter().collect(); - - if unique_mints.len() != config_supported_mints.len() { - return Err(TipRouterError::DuplicateMintsInTable); - } - - // Set table using iterator - self.table - .iter_mut() - .zip(config_supported_mints.iter()) - .for_each(|(entry, &mint)| { - *entry = WeightEntry::new(mint); - }); + ncn_fees: Fees, - self.check_initialized()?; + num_operators: PodU16, + operators_registered: PodU16, - Ok(()) - } - - pub fn set_weight( - &mut self, - mint: &Pubkey, - weight: u128, - current_slot: u64, - ) -> Result<(), TipRouterError> { - self.table - .iter_mut() - .find(|entry| entry.mint() == *mint) - .map_or(Err(TipRouterError::InvalidMintForWeightTable), |entry| { - entry.set_weight(weight, current_slot); - Ok(()) - }) - } - - pub fn get_weight(&self, mint: &Pubkey) -> Result { - self.table - .iter() - .find(|entry| entry.mint() == *mint) - .map_or(Err(TipRouterError::InvalidMintForWeightTable), |entry| { - Ok(entry.weight()) - }) - } - - pub fn get_mints(&self) -> Vec { - self.table - .iter() - .filter(|entry| !entry.is_empty()) - .map(|entry| entry.mint()) - .collect() - } - - pub fn find_weight(&self, mint: &Pubkey) -> Option { - self.table - .iter() - .find(|entry| entry.mint() == *mint) - .map(|entry| entry.weight()) - } - - pub fn mint_count(&self) -> usize { - self.table.iter().filter(|entry| !entry.is_empty()).count() - } - - pub fn weight_count(&self) -> usize { - self.table.iter().filter(|entry| !entry.is_set()).count() - } - - pub const fn ncn(&self) -> Pubkey { - self.ncn - } - - pub fn ncn_epoch(&self) -> u64 { - self.ncn_epoch.into() - } - - pub fn slot_created(&self) -> u64 { - self.slot_created.into() - } - - pub fn initialized(&self) -> bool { - self.mint_count() > 0 - } - - pub fn finalized(&self) -> bool { - self.initialized() && self.mint_count() == self.weight_count() - } - - pub fn check_initialized(&self) -> Result<(), TipRouterError> { - if !self.initialized() { - return Err(TipRouterError::NoMintsInTable); - } - Ok(()) - } - - pub fn load( - program_id: &Pubkey, - weight_table: &AccountInfo, - ncn: &AccountInfo, - ncn_epoch: u64, - expect_writable: bool, - ) -> Result<(), ProgramError> { - if weight_table.owner.ne(program_id) { - msg!("Weight table account is not owned by the program"); - return Err(ProgramError::InvalidAccountOwner); - } - if weight_table.data_is_empty() { - msg!("Weight table account is empty"); - return Err(ProgramError::InvalidAccountData); - } - if expect_writable && !weight_table.is_writable { - msg!("Weight table account is not writable"); - return Err(ProgramError::InvalidAccountData); - } - if weight_table.data.borrow()[0].ne(&Self::DISCRIMINATOR) { - msg!("Weight table account has an incorrect discriminator"); - return Err(ProgramError::InvalidAccountData); - } - let expected_pubkey = Self::find_program_address(program_id, ncn.key, ncn_epoch).0; - if weight_table.key.ne(&expected_pubkey) { - msg!("Weight table incorrect PDA"); - return Err(ProgramError::InvalidAccountData); - } - Ok(()) - } + /// Counted as each delegate gets added + total_votes: PodU128, } -#[cfg(test)] -mod tests { - use solana_program::pubkey::Pubkey; - - use super::*; - - fn get_test_pubkeys(count: usize) -> Vec { - (0..count).map(|_| Pubkey::new_unique()).collect() - } - - #[test] - fn test_initialize_table_success() { - let ncn = Pubkey::new_unique(); - let mut table = WeightTable::new(ncn, 0, 0, 0); - assert_eq!(table.mint_count(), 0); - - let mints = get_test_pubkeys(2); - table.initalize_weight_table(&mints).unwrap(); - assert_eq!(table.mint_count(), 2); - } - - #[test] - fn test_initialize_table_too_many() { - let ncn = Pubkey::new_unique(); - let mut table = WeightTable::new(ncn, 0, 0, 0); - let many_mints = get_test_pubkeys(WeightTable::MAX_TABLE_ENTRIES + 1); - assert_eq!( - table.initalize_weight_table(&many_mints), - Err(TipRouterError::TooManyMintsForTable) - ); - } - - #[test] - fn test_initialize_table_max() { - let ncn = Pubkey::new_unique(); - let mut table = WeightTable::new(ncn, 0, 0, 0); - let max_mints = get_test_pubkeys(WeightTable::MAX_TABLE_ENTRIES); - table.initalize_weight_table(&max_mints).unwrap(); - assert_eq!(table.mint_count(), WeightTable::MAX_TABLE_ENTRIES); - } - - #[test] - fn test_initialize_table_reinitialize() { - let ncn = Pubkey::new_unique(); - let mut table = WeightTable::new(ncn, 0, 0, 0); - let first_mints = get_test_pubkeys(2); - table.initalize_weight_table(&first_mints).unwrap(); - let second_mints = get_test_pubkeys(3); - - assert_eq!( - table.initalize_weight_table(&second_mints), - Err(TipRouterError::WeightTableAlreadyInitialized) - ); - } - - #[test] - fn test_set_weight_success() { - let ncn = Pubkey::new_unique(); - let mut table = WeightTable::new(ncn, 0, 0, 0); - let mints = get_test_pubkeys(2); - let mint = mints[0]; - - table.initalize_weight_table(&mints).unwrap(); - - table.set_weight(&mint, 100, 1).unwrap(); - assert_eq!(table.get_weight(&mint).unwrap(), 100); - } - - #[test] - fn test_set_weight_invalid_mint() { - let ncn = Pubkey::new_unique(); - let mut table = WeightTable::new(ncn, 0, 0, 0); - let mints = get_test_pubkeys(2); - - table.initalize_weight_table(&mints).unwrap(); - - let invalid_mint = Pubkey::new_unique(); - assert_eq!( - table.set_weight(&invalid_mint, 100, 1), - Err(TipRouterError::InvalidMintForWeightTable) - ); - } - - #[test] - fn test_set_weight_update_existing() { - let ncn = Pubkey::new_unique(); - let mut table = WeightTable::new(ncn, 0, 0, 0); - let mints = get_test_pubkeys(2); - let mint = mints[0]; - - table.initalize_weight_table(&mints).unwrap(); - - table.set_weight(&mint, 100, 1).unwrap(); - assert_eq!(table.get_weight(&mint).unwrap(), 100); - - table.set_weight(&mint, 200, 2).unwrap(); - assert_eq!(table.get_weight(&mint).unwrap(), 200); - } +impl Discriminator for EpochSnapshot { + const DISCRIMINATOR: u8 = Discriminators::EpochSnapshot as u8; +} - #[test] - fn test_set_weight_multiple_mints() { - let ncn = Pubkey::new_unique(); - let mut table = WeightTable::new(ncn, 0, 0, 0); - let mints = get_test_pubkeys(2); - let mint1 = mints[0]; - let mint2 = mints[1]; +// PDA'd ["OPERATOR_SNAPSHOT", OPERATOR, NCN, NCN_EPOCH_SLOT] +#[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] +#[repr(C)] +pub struct OperatorSnapshot { + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: PodU64, + slot_created: PodU64, - table.initalize_weight_table(&mints).unwrap(); + bump: u8, - table.set_weight(&mint1, 100, 1).unwrap(); - table.set_weight(&mint2, 200, 1).unwrap(); + operator_fee_bps: PodU16, - assert_eq!(table.get_weight(&mint1).unwrap(), 100); - assert_eq!(table.get_weight(&mint2).unwrap(), 200); - } + total_votes: PodU128, - #[test] - fn test_set_weight_different_slots() { - let ncn = Pubkey::new_unique(); - let mut table = WeightTable::new(ncn, 0, 0, 0); - let mints = get_test_pubkeys(2); - let mint = mints[0]; + num_vault_operator_delegations: PodU16, + vault_operator_delegations_registered: PodU16, - table.initalize_weight_table(&mints).unwrap(); + slot_set: PodU64, + vault_operator_delegations: [VaultOperatorDelegationSnapshot; 256], +} - table.set_weight(&mint, 100, 1).unwrap(); - assert_eq!(table.get_weight(&mint).unwrap(), 100); +impl Discriminator for OperatorSnapshot { + const DISCRIMINATOR: u8 = Discriminators::OperatorSnapshot as u8; +} - table.set_weight(&mint, 200, 5).unwrap(); - assert_eq!(table.get_weight(&mint).unwrap(), 200); - } +// Operators effectively cast N types of votes, +// where N is the number of supported mints +#[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod)] +#[repr(C)] +pub struct VaultOperatorDelegationSnapshot { + vault: Pubkey, + st_mint: Pubkey, + delegation_state: DelegationState, + total_votes: PodU128, + slot_set: PodU64, + reserved: [u8; 128], } diff --git a/core/src/ncn_config.rs b/core/src/ncn_config.rs index d7f72bb..51765cb 100644 --- a/core/src/ncn_config.rs +++ b/core/src/ncn_config.rs @@ -36,7 +36,7 @@ pub struct NcnConfig { } impl Discriminator for NcnConfig { - const DISCRIMINATOR: u8 = Discriminators::Config as u8; + const DISCRIMINATOR: u8 = Discriminators::NCNConfig as u8; } impl NcnConfig { From 4d58ac5a84424c578b9a918e422bf90b84db5540 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Mon, 11 Nov 2024 12:29:19 -0800 Subject: [PATCH 03/28] getting closer --- .../jito_tip_router/accounts/epochSnapshot.ts | 164 +++++ clients/js/jito_tip_router/accounts/index.ts | 2 + .../accounts/operatorSnapshot.ts | 197 ++++++ .../jito_tip_router/errors/jitoTipRouter.ts | 18 +- .../js/jito_tip_router/instructions/index.ts | 1 + .../instructions/initializeEpochSnapshot.ts | 300 +++++++++ .../jito_tip_router/programs/jitoTipRouter.ts | 12 +- clients/js/jito_tip_router/types/index.ts | 1 + .../types/vaultOperatorDelegationSnapshot.ts | 77 +++ .../src/generated/accounts/epoch_snapshot.rs | 74 +++ .../src/generated/accounts/mod.rs | 4 +- .../generated/accounts/operator_snapshot.rs | 81 +++ .../src/generated/errors/jito_tip_router.rs | 22 +- .../instructions/initialize_epoch_snapshot.rs | 605 ++++++++++++++++++ .../src/generated/instructions/mod.rs | 5 +- .../src/generated/types/mod.rs | 6 +- .../vault_operator_delegation_snapshot.rs | 28 + core/src/epoch_snapshot.rs | 263 +++++++- core/src/error.rs | 12 +- core/src/instruction.rs | 30 +- core/src/lib.rs | 1 + core/src/loaders.rs | 33 + core/src/weight_table.rs | 13 +- idl/jito_tip_router.json | 261 +++++++- .../tests/fixtures/tip_router_client.rs | 53 +- .../tip_router/initialize_epoch_snapshot.rs | 33 + integration_tests/tests/tip_router/mod.rs | 1 + program/src/finalize_weight_table.rs | 51 -- program/src/initialize_epoch_snapshot.rs | 107 ++++ program/src/initialize_operator_snapshot.rs | 124 ++++ program/src/initialize_weight_table.rs | 46 +- program/src/lib.rs | 30 +- 32 files changed, 2517 insertions(+), 138 deletions(-) create mode 100644 clients/js/jito_tip_router/accounts/epochSnapshot.ts create mode 100644 clients/js/jito_tip_router/accounts/operatorSnapshot.ts create mode 100644 clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts create mode 100644 clients/js/jito_tip_router/types/vaultOperatorDelegationSnapshot.ts create mode 100644 clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs create mode 100644 clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs create mode 100644 clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs create mode 100644 clients/rust/jito_tip_router/src/generated/types/vault_operator_delegation_snapshot.rs create mode 100644 core/src/loaders.rs create mode 100644 integration_tests/tests/tip_router/initialize_epoch_snapshot.rs delete mode 100644 program/src/finalize_weight_table.rs create mode 100644 program/src/initialize_epoch_snapshot.rs create mode 100644 program/src/initialize_operator_snapshot.rs diff --git a/clients/js/jito_tip_router/accounts/epochSnapshot.ts b/clients/js/jito_tip_router/accounts/epochSnapshot.ts new file mode 100644 index 0000000..3c6a279 --- /dev/null +++ b/clients/js/jito_tip_router/accounts/epochSnapshot.ts @@ -0,0 +1,164 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/kinobi-so/kinobi + */ + +import { + assertAccountExists, + assertAccountsExist, + combineCodec, + decodeAccount, + fetchEncodedAccount, + fetchEncodedAccounts, + getAddressDecoder, + getAddressEncoder, + getArrayDecoder, + getArrayEncoder, + getStructDecoder, + getStructEncoder, + getU128Decoder, + getU128Encoder, + getU64Decoder, + getU64Encoder, + getU8Decoder, + getU8Encoder, + type Account, + type Address, + type Codec, + type Decoder, + type EncodedAccount, + type Encoder, + type FetchAccountConfig, + type FetchAccountsConfig, + type MaybeAccount, + type MaybeEncodedAccount, +} from '@solana/web3.js'; +import { + getFeesDecoder, + getFeesEncoder, + type Fees, + type FeesArgs, +} from '../types'; + +export type EpochSnapshot = { + discriminator: bigint; + ncn: Address; + ncnEpoch: bigint; + slotCreated: bigint; + bump: number; + ncnFees: Fees; + operatorCount: bigint; + operatorsRegistered: bigint; + totalVotes: bigint; + reserved: Array; +}; + +export type EpochSnapshotArgs = { + discriminator: number | bigint; + ncn: Address; + ncnEpoch: number | bigint; + slotCreated: number | bigint; + bump: number; + ncnFees: FeesArgs; + operatorCount: number | bigint; + operatorsRegistered: number | bigint; + totalVotes: number | bigint; + reserved: Array; +}; + +export function getEpochSnapshotEncoder(): Encoder { + return getStructEncoder([ + ['discriminator', getU64Encoder()], + ['ncn', getAddressEncoder()], + ['ncnEpoch', getU64Encoder()], + ['slotCreated', getU64Encoder()], + ['bump', getU8Encoder()], + ['ncnFees', getFeesEncoder()], + ['operatorCount', getU64Encoder()], + ['operatorsRegistered', getU64Encoder()], + ['totalVotes', getU128Encoder()], + ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], + ]); +} + +export function getEpochSnapshotDecoder(): Decoder { + return getStructDecoder([ + ['discriminator', getU64Decoder()], + ['ncn', getAddressDecoder()], + ['ncnEpoch', getU64Decoder()], + ['slotCreated', getU64Decoder()], + ['bump', getU8Decoder()], + ['ncnFees', getFeesDecoder()], + ['operatorCount', getU64Decoder()], + ['operatorsRegistered', getU64Decoder()], + ['totalVotes', getU128Decoder()], + ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], + ]); +} + +export function getEpochSnapshotCodec(): Codec< + EpochSnapshotArgs, + EpochSnapshot +> { + return combineCodec(getEpochSnapshotEncoder(), getEpochSnapshotDecoder()); +} + +export function decodeEpochSnapshot( + encodedAccount: EncodedAccount +): Account; +export function decodeEpochSnapshot( + encodedAccount: MaybeEncodedAccount +): MaybeAccount; +export function decodeEpochSnapshot( + encodedAccount: EncodedAccount | MaybeEncodedAccount +): Account | MaybeAccount { + return decodeAccount( + encodedAccount as MaybeEncodedAccount, + getEpochSnapshotDecoder() + ); +} + +export async function fetchEpochSnapshot( + rpc: Parameters[0], + address: Address, + config?: FetchAccountConfig +): Promise> { + const maybeAccount = await fetchMaybeEpochSnapshot(rpc, address, config); + assertAccountExists(maybeAccount); + return maybeAccount; +} + +export async function fetchMaybeEpochSnapshot( + rpc: Parameters[0], + address: Address, + config?: FetchAccountConfig +): Promise> { + const maybeAccount = await fetchEncodedAccount(rpc, address, config); + return decodeEpochSnapshot(maybeAccount); +} + +export async function fetchAllEpochSnapshot( + rpc: Parameters[0], + addresses: Array
, + config?: FetchAccountsConfig +): Promise[]> { + const maybeAccounts = await fetchAllMaybeEpochSnapshot( + rpc, + addresses, + config + ); + assertAccountsExist(maybeAccounts); + return maybeAccounts; +} + +export async function fetchAllMaybeEpochSnapshot( + rpc: Parameters[0], + addresses: Array
, + config?: FetchAccountsConfig +): Promise[]> { + const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config); + return maybeAccounts.map((maybeAccount) => decodeEpochSnapshot(maybeAccount)); +} diff --git a/clients/js/jito_tip_router/accounts/index.ts b/clients/js/jito_tip_router/accounts/index.ts index 033882c..6fa7098 100644 --- a/clients/js/jito_tip_router/accounts/index.ts +++ b/clients/js/jito_tip_router/accounts/index.ts @@ -6,5 +6,7 @@ * @see https://github.com/kinobi-so/kinobi */ +export * from './epochSnapshot'; export * from './ncnConfig'; +export * from './operatorSnapshot'; export * from './weightTable'; diff --git a/clients/js/jito_tip_router/accounts/operatorSnapshot.ts b/clients/js/jito_tip_router/accounts/operatorSnapshot.ts new file mode 100644 index 0000000..ae46a96 --- /dev/null +++ b/clients/js/jito_tip_router/accounts/operatorSnapshot.ts @@ -0,0 +1,197 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/kinobi-so/kinobi + */ + +import { + assertAccountExists, + assertAccountsExist, + combineCodec, + decodeAccount, + fetchEncodedAccount, + fetchEncodedAccounts, + getAddressDecoder, + getAddressEncoder, + getArrayDecoder, + getArrayEncoder, + getStructDecoder, + getStructEncoder, + getU128Decoder, + getU128Encoder, + getU16Decoder, + getU16Encoder, + getU64Decoder, + getU64Encoder, + getU8Decoder, + getU8Encoder, + type Account, + type Address, + type Codec, + type Decoder, + type EncodedAccount, + type Encoder, + type FetchAccountConfig, + type FetchAccountsConfig, + type MaybeAccount, + type MaybeEncodedAccount, +} from '@solana/web3.js'; +import { + getVaultOperatorDelegationSnapshotDecoder, + getVaultOperatorDelegationSnapshotEncoder, + type VaultOperatorDelegationSnapshot, + type VaultOperatorDelegationSnapshotArgs, +} from '../types'; + +export type OperatorSnapshot = { + discriminator: bigint; + operator: Address; + ncn: Address; + ncnEpoch: bigint; + slotCreated: bigint; + bump: number; + operatorFeeBps: number; + totalVotes: bigint; + numVaultOperatorDelegations: number; + vaultOperatorDelegationsRegistered: number; + slotSet: bigint; + vaultOperatorDelegations: Array; + reserved: Array; +}; + +export type OperatorSnapshotArgs = { + discriminator: number | bigint; + operator: Address; + ncn: Address; + ncnEpoch: number | bigint; + slotCreated: number | bigint; + bump: number; + operatorFeeBps: number; + totalVotes: number | bigint; + numVaultOperatorDelegations: number; + vaultOperatorDelegationsRegistered: number; + slotSet: number | bigint; + vaultOperatorDelegations: Array; + reserved: Array; +}; + +export function getOperatorSnapshotEncoder(): Encoder { + return getStructEncoder([ + ['discriminator', getU64Encoder()], + ['operator', getAddressEncoder()], + ['ncn', getAddressEncoder()], + ['ncnEpoch', getU64Encoder()], + ['slotCreated', getU64Encoder()], + ['bump', getU8Encoder()], + ['operatorFeeBps', getU16Encoder()], + ['totalVotes', getU128Encoder()], + ['numVaultOperatorDelegations', getU16Encoder()], + ['vaultOperatorDelegationsRegistered', getU16Encoder()], + ['slotSet', getU64Encoder()], + [ + 'vaultOperatorDelegations', + getArrayEncoder(getVaultOperatorDelegationSnapshotEncoder(), { + size: 32, + }), + ], + ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], + ]); +} + +export function getOperatorSnapshotDecoder(): Decoder { + return getStructDecoder([ + ['discriminator', getU64Decoder()], + ['operator', getAddressDecoder()], + ['ncn', getAddressDecoder()], + ['ncnEpoch', getU64Decoder()], + ['slotCreated', getU64Decoder()], + ['bump', getU8Decoder()], + ['operatorFeeBps', getU16Decoder()], + ['totalVotes', getU128Decoder()], + ['numVaultOperatorDelegations', getU16Decoder()], + ['vaultOperatorDelegationsRegistered', getU16Decoder()], + ['slotSet', getU64Decoder()], + [ + 'vaultOperatorDelegations', + getArrayDecoder(getVaultOperatorDelegationSnapshotDecoder(), { + size: 32, + }), + ], + ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], + ]); +} + +export function getOperatorSnapshotCodec(): Codec< + OperatorSnapshotArgs, + OperatorSnapshot +> { + return combineCodec( + getOperatorSnapshotEncoder(), + getOperatorSnapshotDecoder() + ); +} + +export function decodeOperatorSnapshot( + encodedAccount: EncodedAccount +): Account; +export function decodeOperatorSnapshot( + encodedAccount: MaybeEncodedAccount +): MaybeAccount; +export function decodeOperatorSnapshot( + encodedAccount: EncodedAccount | MaybeEncodedAccount +): + | Account + | MaybeAccount { + return decodeAccount( + encodedAccount as MaybeEncodedAccount, + getOperatorSnapshotDecoder() + ); +} + +export async function fetchOperatorSnapshot( + rpc: Parameters[0], + address: Address, + config?: FetchAccountConfig +): Promise> { + const maybeAccount = await fetchMaybeOperatorSnapshot(rpc, address, config); + assertAccountExists(maybeAccount); + return maybeAccount; +} + +export async function fetchMaybeOperatorSnapshot< + TAddress extends string = string, +>( + rpc: Parameters[0], + address: Address, + config?: FetchAccountConfig +): Promise> { + const maybeAccount = await fetchEncodedAccount(rpc, address, config); + return decodeOperatorSnapshot(maybeAccount); +} + +export async function fetchAllOperatorSnapshot( + rpc: Parameters[0], + addresses: Array
, + config?: FetchAccountsConfig +): Promise[]> { + const maybeAccounts = await fetchAllMaybeOperatorSnapshot( + rpc, + addresses, + config + ); + assertAccountsExist(maybeAccounts); + return maybeAccounts; +} + +export async function fetchAllMaybeOperatorSnapshot( + rpc: Parameters[0], + addresses: Array
, + config?: FetchAccountsConfig +): Promise[]> { + const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config); + return maybeAccounts.map((maybeAccount) => + decodeOperatorSnapshot(maybeAccount) + ); +} diff --git a/clients/js/jito_tip_router/errors/jitoTipRouter.ts b/clients/js/jito_tip_router/errors/jitoTipRouter.ts index 45ac3fa..62f7679 100644 --- a/clients/js/jito_tip_router/errors/jitoTipRouter.ts +++ b/clients/js/jito_tip_router/errors/jitoTipRouter.ts @@ -43,13 +43,17 @@ export const JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_MINT_HASH = 0x2207 /** InvalidMintForWeightTable: Invalid mint for weight table */ export const JITO_TIP_ROUTER_ERROR__INVALID_MINT_FOR_WEIGHT_TABLE = 0x2208; // 8712 /** FeeCapExceeded: Fee cap exceeded */ -export const JITO_TIP_ROUTER_ERROR__FEE_CAP_EXCEEDED = 0x2300; // 8960 +export const JITO_TIP_ROUTER_ERROR__FEE_CAP_EXCEEDED = 0x2209; // 8713 /** IncorrectNcnAdmin: Incorrect NCN Admin */ -export const JITO_TIP_ROUTER_ERROR__INCORRECT_NCN_ADMIN = 0x2400; // 9216 +export const JITO_TIP_ROUTER_ERROR__INCORRECT_NCN_ADMIN = 0x220a; // 8714 /** IncorrectNcn: Incorrect NCN */ -export const JITO_TIP_ROUTER_ERROR__INCORRECT_NCN = 0x2401; // 9217 +export const JITO_TIP_ROUTER_ERROR__INCORRECT_NCN = 0x220b; // 8715 /** IncorrectFeeAdmin: Incorrect fee admin */ -export const JITO_TIP_ROUTER_ERROR__INCORRECT_FEE_ADMIN = 0x2402; // 9218 +export const JITO_TIP_ROUTER_ERROR__INCORRECT_FEE_ADMIN = 0x220c; // 8716 +/** WeightTableNotFinalized: Weight table not finalized */ +export const JITO_TIP_ROUTER_ERROR__WEIGHT_TABLE_NOT_FINALIZED = 0x220d; // 8717 +/** WeightNotFound: Weight not found */ +export const JITO_TIP_ROUTER_ERROR__WEIGHT_NOT_FOUND = 0x220e; // 8718 export type JitoTipRouterError = | typeof JITO_TIP_ROUTER_ERROR__ARITHMETIC_OVERFLOW @@ -69,7 +73,9 @@ export type JitoTipRouterError = | typeof JITO_TIP_ROUTER_ERROR__TOO_MANY_MINTS_FOR_TABLE | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_LENGTH | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_MINT_HASH - | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_TABLE_ALREADY_INITIALIZED; + | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_NOT_FOUND + | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_TABLE_ALREADY_INITIALIZED + | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_TABLE_NOT_FINALIZED; let jitoTipRouterErrorMessages: Record | undefined; if (process.env.NODE_ENV !== 'production') { @@ -91,7 +97,9 @@ if (process.env.NODE_ENV !== 'production') { [JITO_TIP_ROUTER_ERROR__TOO_MANY_MINTS_FOR_TABLE]: `Too many mints for table`, [JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_LENGTH]: `Weight mints do not match - length`, [JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_MINT_HASH]: `Weight mints do not match - mint hash`, + [JITO_TIP_ROUTER_ERROR__WEIGHT_NOT_FOUND]: `Weight not found`, [JITO_TIP_ROUTER_ERROR__WEIGHT_TABLE_ALREADY_INITIALIZED]: `Weight table already initialized`, + [JITO_TIP_ROUTER_ERROR__WEIGHT_TABLE_NOT_FINALIZED]: `Weight table not finalized`, }; } diff --git a/clients/js/jito_tip_router/instructions/index.ts b/clients/js/jito_tip_router/instructions/index.ts index 5be6407..18c4550 100644 --- a/clients/js/jito_tip_router/instructions/index.ts +++ b/clients/js/jito_tip_router/instructions/index.ts @@ -7,6 +7,7 @@ */ export * from './adminUpdateWeightTable'; +export * from './initializeEpochSnapshot'; export * from './initializeNCNConfig'; export * from './initializeWeightTable'; export * from './setConfigFees'; diff --git a/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts b/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts new file mode 100644 index 0000000..1e9857d --- /dev/null +++ b/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts @@ -0,0 +1,300 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/kinobi-so/kinobi + */ + +import { + combineCodec, + getOptionDecoder, + getOptionEncoder, + getStructDecoder, + getStructEncoder, + getU64Decoder, + getU64Encoder, + getU8Decoder, + getU8Encoder, + transformEncoder, + type Address, + type Codec, + type Decoder, + type Encoder, + type IAccountMeta, + type IAccountSignerMeta, + type IInstruction, + type IInstructionWithAccounts, + type IInstructionWithData, + type Option, + type OptionOrNullable, + type ReadonlyAccount, + type TransactionSigner, + type WritableAccount, + type WritableSignerAccount, +} from '@solana/web3.js'; +import { JITO_TIP_ROUTER_PROGRAM_ADDRESS } from '../programs'; +import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; + +export const INITIALIZE_EPOCH_SNAPSHOT_DISCRIMINATOR = 5; + +export function getInitializeEpochSnapshotDiscriminatorBytes() { + return getU8Encoder().encode(INITIALIZE_EPOCH_SNAPSHOT_DISCRIMINATOR); +} + +export type InitializeEpochSnapshotInstruction< + TProgram extends string = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, + TAccountNcnConfig extends string | IAccountMeta = string, + TAccountRestakingConfig extends string | IAccountMeta = string, + TAccountNcn extends string | IAccountMeta = string, + TAccountWeightTable extends string | IAccountMeta = string, + TAccountEpochSnapshot extends string | IAccountMeta = string, + TAccountPayer extends string | IAccountMeta = string, + TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountSystemProgram extends + | string + | IAccountMeta = '11111111111111111111111111111111', + TRemainingAccounts extends readonly IAccountMeta[] = [], +> = IInstruction & + IInstructionWithData & + IInstructionWithAccounts< + [ + TAccountNcnConfig extends string + ? ReadonlyAccount + : TAccountNcnConfig, + TAccountRestakingConfig extends string + ? ReadonlyAccount + : TAccountRestakingConfig, + TAccountNcn extends string ? ReadonlyAccount : TAccountNcn, + TAccountWeightTable extends string + ? ReadonlyAccount + : TAccountWeightTable, + TAccountEpochSnapshot extends string + ? WritableAccount + : TAccountEpochSnapshot, + TAccountPayer extends string + ? WritableSignerAccount & + IAccountSignerMeta + : TAccountPayer, + TAccountRestakingProgramId extends string + ? ReadonlyAccount + : TAccountRestakingProgramId, + TAccountSystemProgram extends string + ? ReadonlyAccount + : TAccountSystemProgram, + ...TRemainingAccounts, + ] + >; + +export type InitializeEpochSnapshotInstructionData = { + discriminator: number; + firstSlotOfNcnEpoch: Option; +}; + +export type InitializeEpochSnapshotInstructionDataArgs = { + firstSlotOfNcnEpoch: OptionOrNullable; +}; + +export function getInitializeEpochSnapshotInstructionDataEncoder(): Encoder { + return transformEncoder( + getStructEncoder([ + ['discriminator', getU8Encoder()], + ['firstSlotOfNcnEpoch', getOptionEncoder(getU64Encoder())], + ]), + (value) => ({ + ...value, + discriminator: INITIALIZE_EPOCH_SNAPSHOT_DISCRIMINATOR, + }) + ); +} + +export function getInitializeEpochSnapshotInstructionDataDecoder(): Decoder { + return getStructDecoder([ + ['discriminator', getU8Decoder()], + ['firstSlotOfNcnEpoch', getOptionDecoder(getU64Decoder())], + ]); +} + +export function getInitializeEpochSnapshotInstructionDataCodec(): Codec< + InitializeEpochSnapshotInstructionDataArgs, + InitializeEpochSnapshotInstructionData +> { + return combineCodec( + getInitializeEpochSnapshotInstructionDataEncoder(), + getInitializeEpochSnapshotInstructionDataDecoder() + ); +} + +export type InitializeEpochSnapshotInput< + TAccountNcnConfig extends string = string, + TAccountRestakingConfig extends string = string, + TAccountNcn extends string = string, + TAccountWeightTable extends string = string, + TAccountEpochSnapshot extends string = string, + TAccountPayer extends string = string, + TAccountRestakingProgramId extends string = string, + TAccountSystemProgram extends string = string, +> = { + ncnConfig: Address; + restakingConfig: Address; + ncn: Address; + weightTable: Address; + epochSnapshot: Address; + payer: TransactionSigner; + restakingProgramId: Address; + systemProgram?: Address; + firstSlotOfNcnEpoch: InitializeEpochSnapshotInstructionDataArgs['firstSlotOfNcnEpoch']; +}; + +export function getInitializeEpochSnapshotInstruction< + TAccountNcnConfig extends string, + TAccountRestakingConfig extends string, + TAccountNcn extends string, + TAccountWeightTable extends string, + TAccountEpochSnapshot extends string, + TAccountPayer extends string, + TAccountRestakingProgramId extends string, + TAccountSystemProgram extends string, + TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, +>( + input: InitializeEpochSnapshotInput< + TAccountNcnConfig, + TAccountRestakingConfig, + TAccountNcn, + TAccountWeightTable, + TAccountEpochSnapshot, + TAccountPayer, + TAccountRestakingProgramId, + TAccountSystemProgram + >, + config?: { programAddress?: TProgramAddress } +): InitializeEpochSnapshotInstruction< + TProgramAddress, + TAccountNcnConfig, + TAccountRestakingConfig, + TAccountNcn, + TAccountWeightTable, + TAccountEpochSnapshot, + TAccountPayer, + TAccountRestakingProgramId, + TAccountSystemProgram +> { + // Program address. + const programAddress = + config?.programAddress ?? JITO_TIP_ROUTER_PROGRAM_ADDRESS; + + // Original accounts. + const originalAccounts = { + ncnConfig: { value: input.ncnConfig ?? null, isWritable: false }, + restakingConfig: { + value: input.restakingConfig ?? null, + isWritable: false, + }, + ncn: { value: input.ncn ?? null, isWritable: false }, + weightTable: { value: input.weightTable ?? null, isWritable: false }, + epochSnapshot: { value: input.epochSnapshot ?? null, isWritable: true }, + payer: { value: input.payer ?? null, isWritable: true }, + restakingProgramId: { + value: input.restakingProgramId ?? null, + isWritable: false, + }, + systemProgram: { value: input.systemProgram ?? null, isWritable: false }, + }; + const accounts = originalAccounts as Record< + keyof typeof originalAccounts, + ResolvedAccount + >; + + // Original args. + const args = { ...input }; + + // Resolve default values. + if (!accounts.systemProgram.value) { + accounts.systemProgram.value = + '11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>; + } + + const getAccountMeta = getAccountMetaFactory(programAddress, 'programId'); + const instruction = { + accounts: [ + getAccountMeta(accounts.ncnConfig), + getAccountMeta(accounts.restakingConfig), + getAccountMeta(accounts.ncn), + getAccountMeta(accounts.weightTable), + getAccountMeta(accounts.epochSnapshot), + getAccountMeta(accounts.payer), + getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.systemProgram), + ], + programAddress, + data: getInitializeEpochSnapshotInstructionDataEncoder().encode( + args as InitializeEpochSnapshotInstructionDataArgs + ), + } as InitializeEpochSnapshotInstruction< + TProgramAddress, + TAccountNcnConfig, + TAccountRestakingConfig, + TAccountNcn, + TAccountWeightTable, + TAccountEpochSnapshot, + TAccountPayer, + TAccountRestakingProgramId, + TAccountSystemProgram + >; + + return instruction; +} + +export type ParsedInitializeEpochSnapshotInstruction< + TProgram extends string = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, + TAccountMetas extends readonly IAccountMeta[] = readonly IAccountMeta[], +> = { + programAddress: Address; + accounts: { + ncnConfig: TAccountMetas[0]; + restakingConfig: TAccountMetas[1]; + ncn: TAccountMetas[2]; + weightTable: TAccountMetas[3]; + epochSnapshot: TAccountMetas[4]; + payer: TAccountMetas[5]; + restakingProgramId: TAccountMetas[6]; + systemProgram: TAccountMetas[7]; + }; + data: InitializeEpochSnapshotInstructionData; +}; + +export function parseInitializeEpochSnapshotInstruction< + TProgram extends string, + TAccountMetas extends readonly IAccountMeta[], +>( + instruction: IInstruction & + IInstructionWithAccounts & + IInstructionWithData +): ParsedInitializeEpochSnapshotInstruction { + if (instruction.accounts.length < 8) { + // TODO: Coded error. + throw new Error('Not enough accounts'); + } + let accountIndex = 0; + const getNextAccount = () => { + const accountMeta = instruction.accounts![accountIndex]!; + accountIndex += 1; + return accountMeta; + }; + return { + programAddress: instruction.programAddress, + accounts: { + ncnConfig: getNextAccount(), + restakingConfig: getNextAccount(), + ncn: getNextAccount(), + weightTable: getNextAccount(), + epochSnapshot: getNextAccount(), + payer: getNextAccount(), + restakingProgramId: getNextAccount(), + systemProgram: getNextAccount(), + }, + data: getInitializeEpochSnapshotInstructionDataDecoder().decode( + instruction.data + ), + }; +} diff --git a/clients/js/jito_tip_router/programs/jitoTipRouter.ts b/clients/js/jito_tip_router/programs/jitoTipRouter.ts index c3f29cd..f23e413 100644 --- a/clients/js/jito_tip_router/programs/jitoTipRouter.ts +++ b/clients/js/jito_tip_router/programs/jitoTipRouter.ts @@ -14,6 +14,7 @@ import { } from '@solana/web3.js'; import { type ParsedAdminUpdateWeightTableInstruction, + type ParsedInitializeEpochSnapshotInstruction, type ParsedInitializeNCNConfigInstruction, type ParsedInitializeWeightTableInstruction, type ParsedSetConfigFeesInstruction, @@ -24,6 +25,8 @@ export const JITO_TIP_ROUTER_PROGRAM_ADDRESS = 'Fv9aHCgvPQSr4jg9W8eTS6Ys1SNmh2qjyATrbsjEMaSH' as Address<'Fv9aHCgvPQSr4jg9W8eTS6Ys1SNmh2qjyATrbsjEMaSH'>; export enum JitoTipRouterAccount { + EpochSnapshot, + OperatorSnapshot, NcnConfig, WeightTable, } @@ -34,6 +37,7 @@ export enum JitoTipRouterInstruction { SetNewAdmin, InitializeWeightTable, AdminUpdateWeightTable, + InitializeEpochSnapshot, } export function identifyJitoTipRouterInstruction( @@ -55,6 +59,9 @@ export function identifyJitoTipRouterInstruction( if (containsBytes(data, getU8Encoder().encode(4), 0)) { return JitoTipRouterInstruction.AdminUpdateWeightTable; } + if (containsBytes(data, getU8Encoder().encode(5), 0)) { + return JitoTipRouterInstruction.InitializeEpochSnapshot; + } throw new Error( 'The provided instruction could not be identified as a jitoTipRouter instruction.' ); @@ -77,4 +84,7 @@ export type ParsedJitoTipRouterInstruction< } & ParsedInitializeWeightTableInstruction) | ({ instructionType: JitoTipRouterInstruction.AdminUpdateWeightTable; - } & ParsedAdminUpdateWeightTableInstruction); + } & ParsedAdminUpdateWeightTableInstruction) + | ({ + instructionType: JitoTipRouterInstruction.InitializeEpochSnapshot; + } & ParsedInitializeEpochSnapshotInstruction); diff --git a/clients/js/jito_tip_router/types/index.ts b/clients/js/jito_tip_router/types/index.ts index a78e605..dd0513a 100644 --- a/clients/js/jito_tip_router/types/index.ts +++ b/clients/js/jito_tip_router/types/index.ts @@ -9,4 +9,5 @@ export * from './configAdminRole'; export * from './fee'; export * from './fees'; +export * from './vaultOperatorDelegationSnapshot'; export * from './weightEntry'; diff --git a/clients/js/jito_tip_router/types/vaultOperatorDelegationSnapshot.ts b/clients/js/jito_tip_router/types/vaultOperatorDelegationSnapshot.ts new file mode 100644 index 0000000..22529c7 --- /dev/null +++ b/clients/js/jito_tip_router/types/vaultOperatorDelegationSnapshot.ts @@ -0,0 +1,77 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/kinobi-so/kinobi + */ + +import { + combineCodec, + getAddressDecoder, + getAddressEncoder, + getArrayDecoder, + getArrayEncoder, + getStructDecoder, + getStructEncoder, + getU128Decoder, + getU128Encoder, + getU64Decoder, + getU64Encoder, + getU8Decoder, + getU8Encoder, + type Address, + type Codec, + type Decoder, + type Encoder, +} from '@solana/web3.js'; + +export type VaultOperatorDelegationSnapshot = { + vault: Address; + stMint: Address; + totalSecurity: bigint; + totalVotes: bigint; + slotSet: bigint; + reserved: Array; +}; + +export type VaultOperatorDelegationSnapshotArgs = { + vault: Address; + stMint: Address; + totalSecurity: number | bigint; + totalVotes: number | bigint; + slotSet: number | bigint; + reserved: Array; +}; + +export function getVaultOperatorDelegationSnapshotEncoder(): Encoder { + return getStructEncoder([ + ['vault', getAddressEncoder()], + ['stMint', getAddressEncoder()], + ['totalSecurity', getU64Encoder()], + ['totalVotes', getU128Encoder()], + ['slotSet', getU64Encoder()], + ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], + ]); +} + +export function getVaultOperatorDelegationSnapshotDecoder(): Decoder { + return getStructDecoder([ + ['vault', getAddressDecoder()], + ['stMint', getAddressDecoder()], + ['totalSecurity', getU64Decoder()], + ['totalVotes', getU128Decoder()], + ['slotSet', getU64Decoder()], + ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], + ]); +} + +export function getVaultOperatorDelegationSnapshotCodec(): Codec< + VaultOperatorDelegationSnapshotArgs, + VaultOperatorDelegationSnapshot +> { + return combineCodec( + getVaultOperatorDelegationSnapshotEncoder(), + getVaultOperatorDelegationSnapshotDecoder() + ); +} diff --git a/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs b/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs new file mode 100644 index 0000000..da51aeb --- /dev/null +++ b/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs @@ -0,0 +1,74 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! + +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +use crate::generated::types::Fees; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct EpochSnapshot { + pub discriminator: u64, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub ncn: Pubkey, + pub ncn_epoch: u64, + pub slot_created: u64, + pub bump: u8, + pub ncn_fees: Fees, + pub operator_count: u64, + pub operators_registered: u64, + pub total_votes: u128, + #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] + pub reserved: [u8; 128], +} + +impl EpochSnapshot { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> for EpochSnapshot { + type Error = std::io::Error; + + fn try_from( + account_info: &solana_program::account_info::AccountInfo<'a>, + ) -> Result { + let mut data: &[u8] = &(*account_info.data).borrow(); + Self::deserialize(&mut data) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for EpochSnapshot { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for EpochSnapshot {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for EpochSnapshot { + fn owner() -> Pubkey { + crate::JITO_TIP_ROUTER_ID + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for EpochSnapshot {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for EpochSnapshot { + const DISCRIMINATOR: [u8; 8] = [0; 8]; +} diff --git a/clients/rust/jito_tip_router/src/generated/accounts/mod.rs b/clients/rust/jito_tip_router/src/generated/accounts/mod.rs index 6feb3df..4655dd2 100644 --- a/clients/rust/jito_tip_router/src/generated/accounts/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/accounts/mod.rs @@ -4,7 +4,9 @@ //! //! +pub(crate) mod r#epoch_snapshot; pub(crate) mod r#ncn_config; +pub(crate) mod r#operator_snapshot; pub(crate) mod r#weight_table; -pub use self::{r#ncn_config::*, r#weight_table::*}; +pub use self::{r#epoch_snapshot::*, r#ncn_config::*, r#operator_snapshot::*, r#weight_table::*}; diff --git a/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs b/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs new file mode 100644 index 0000000..80038f5 --- /dev/null +++ b/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs @@ -0,0 +1,81 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! + +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +use crate::generated::types::VaultOperatorDelegationSnapshot; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct OperatorSnapshot { + pub discriminator: u64, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub operator: Pubkey, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub ncn: Pubkey, + pub ncn_epoch: u64, + pub slot_created: u64, + pub bump: u8, + pub operator_fee_bps: u16, + pub total_votes: u128, + pub num_vault_operator_delegations: u16, + pub vault_operator_delegations_registered: u16, + pub slot_set: u64, + pub vault_operator_delegations: [VaultOperatorDelegationSnapshot; 32], + #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] + pub reserved: [u8; 128], +} + +impl OperatorSnapshot { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> for OperatorSnapshot { + type Error = std::io::Error; + + fn try_from( + account_info: &solana_program::account_info::AccountInfo<'a>, + ) -> Result { + let mut data: &[u8] = &(*account_info.data).borrow(); + Self::deserialize(&mut data) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for OperatorSnapshot { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for OperatorSnapshot {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for OperatorSnapshot { + fn owner() -> Pubkey { + crate::JITO_TIP_ROUTER_ID + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for OperatorSnapshot {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for OperatorSnapshot { + const DISCRIMINATOR: [u8; 8] = [0; 8]; +} diff --git a/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs b/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs index e094476..efaa971 100644 --- a/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs +++ b/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs @@ -51,18 +51,24 @@ pub enum JitoTipRouterError { /// 8712 - Invalid mint for weight table #[error("Invalid mint for weight table")] InvalidMintForWeightTable = 0x2208, - /// 8960 - Fee cap exceeded + /// 8713 - Fee cap exceeded #[error("Fee cap exceeded")] - FeeCapExceeded = 0x2300, - /// 9216 - Incorrect NCN Admin + FeeCapExceeded = 0x2209, + /// 8714 - Incorrect NCN Admin #[error("Incorrect NCN Admin")] - IncorrectNcnAdmin = 0x2400, - /// 9217 - Incorrect NCN + IncorrectNcnAdmin = 0x220A, + /// 8715 - Incorrect NCN #[error("Incorrect NCN")] - IncorrectNcn = 0x2401, - /// 9218 - Incorrect fee admin + IncorrectNcn = 0x220B, + /// 8716 - Incorrect fee admin #[error("Incorrect fee admin")] - IncorrectFeeAdmin = 0x2402, + IncorrectFeeAdmin = 0x220C, + /// 8717 - Weight table not finalized + #[error("Weight table not finalized")] + WeightTableNotFinalized = 0x220D, + /// 8718 - Weight not found + #[error("Weight not found")] + WeightNotFound = 0x220E, } impl solana_program::program_error::PrintProgramError for JitoTipRouterError { diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs new file mode 100644 index 0000000..520d8b9 --- /dev/null +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs @@ -0,0 +1,605 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! + +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct InitializeEpochSnapshot { + pub ncn_config: solana_program::pubkey::Pubkey, + + pub restaking_config: solana_program::pubkey::Pubkey, + + pub ncn: solana_program::pubkey::Pubkey, + + pub weight_table: solana_program::pubkey::Pubkey, + + pub epoch_snapshot: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub restaking_program_id: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl InitializeEpochSnapshot { + pub fn instruction( + &self, + args: InitializeEpochSnapshotInstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: InitializeEpochSnapshotInstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.ncn_config, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.restaking_config, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.ncn, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.weight_table, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.epoch_snapshot, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.restaking_program_id, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = InitializeEpochSnapshotInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::JITO_TIP_ROUTER_ID, + accounts, + data, + } + } +} + +#[derive(BorshDeserialize, BorshSerialize)] +pub struct InitializeEpochSnapshotInstructionData { + discriminator: u8, +} + +impl InitializeEpochSnapshotInstructionData { + pub fn new() -> Self { + Self { discriminator: 5 } + } +} + +impl Default for InitializeEpochSnapshotInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct InitializeEpochSnapshotInstructionArgs { + pub first_slot_of_ncn_epoch: Option, +} + +/// Instruction builder for `InitializeEpochSnapshot`. +/// +/// ### Accounts: +/// +/// 0. `[]` ncn_config +/// 1. `[]` restaking_config +/// 2. `[]` ncn +/// 3. `[]` weight_table +/// 4. `[writable]` epoch_snapshot +/// 5. `[writable, signer]` payer +/// 6. `[]` restaking_program_id +/// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct InitializeEpochSnapshotBuilder { + ncn_config: Option, + restaking_config: Option, + ncn: Option, + weight_table: Option, + epoch_snapshot: Option, + payer: Option, + restaking_program_id: Option, + system_program: Option, + first_slot_of_ncn_epoch: Option, + __remaining_accounts: Vec, +} + +impl InitializeEpochSnapshotBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn ncn_config(&mut self, ncn_config: solana_program::pubkey::Pubkey) -> &mut Self { + self.ncn_config = Some(ncn_config); + self + } + #[inline(always)] + pub fn restaking_config( + &mut self, + restaking_config: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.restaking_config = Some(restaking_config); + self + } + #[inline(always)] + pub fn ncn(&mut self, ncn: solana_program::pubkey::Pubkey) -> &mut Self { + self.ncn = Some(ncn); + self + } + #[inline(always)] + pub fn weight_table(&mut self, weight_table: solana_program::pubkey::Pubkey) -> &mut Self { + self.weight_table = Some(weight_table); + self + } + #[inline(always)] + pub fn epoch_snapshot(&mut self, epoch_snapshot: solana_program::pubkey::Pubkey) -> &mut Self { + self.epoch_snapshot = Some(epoch_snapshot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + #[inline(always)] + pub fn restaking_program_id( + &mut self, + restaking_program_id: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.restaking_program_id = Some(restaking_program_id); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn first_slot_of_ncn_epoch(&mut self, first_slot_of_ncn_epoch: u64) -> &mut Self { + self.first_slot_of_ncn_epoch = Some(first_slot_of_ncn_epoch); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = InitializeEpochSnapshot { + ncn_config: self.ncn_config.expect("ncn_config is not set"), + restaking_config: self.restaking_config.expect("restaking_config is not set"), + ncn: self.ncn.expect("ncn is not set"), + weight_table: self.weight_table.expect("weight_table is not set"), + epoch_snapshot: self.epoch_snapshot.expect("epoch_snapshot is not set"), + payer: self.payer.expect("payer is not set"), + restaking_program_id: self + .restaking_program_id + .expect("restaking_program_id is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = InitializeEpochSnapshotInstructionArgs { + first_slot_of_ncn_epoch: self.first_slot_of_ncn_epoch.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `initialize_epoch_snapshot` CPI accounts. +pub struct InitializeEpochSnapshotCpiAccounts<'a, 'b> { + pub ncn_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn: &'b solana_program::account_info::AccountInfo<'a>, + + pub weight_table: &'b solana_program::account_info::AccountInfo<'a>, + + pub epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `initialize_epoch_snapshot` CPI instruction. +pub struct InitializeEpochSnapshotCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn: &'b solana_program::account_info::AccountInfo<'a>, + + pub weight_table: &'b solana_program::account_info::AccountInfo<'a>, + + pub epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: InitializeEpochSnapshotInstructionArgs, +} + +impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: InitializeEpochSnapshotCpiAccounts<'a, 'b>, + args: InitializeEpochSnapshotInstructionArgs, + ) -> Self { + Self { + __program: program, + ncn_config: accounts.ncn_config, + restaking_config: accounts.restaking_config, + ncn: accounts.ncn, + weight_table: accounts.weight_table, + epoch_snapshot: accounts.epoch_snapshot, + payer: accounts.payer, + restaking_program_id: accounts.restaking_program_id, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.ncn_config.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.restaking_config.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.ncn.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.weight_table.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.epoch_snapshot.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.restaking_program_id.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = InitializeEpochSnapshotInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::JITO_TIP_ROUTER_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(8 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.ncn_config.clone()); + account_infos.push(self.restaking_config.clone()); + account_infos.push(self.ncn.clone()); + account_infos.push(self.weight_table.clone()); + account_infos.push(self.epoch_snapshot.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `InitializeEpochSnapshot` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` ncn_config +/// 1. `[]` restaking_config +/// 2. `[]` ncn +/// 3. `[]` weight_table +/// 4. `[writable]` epoch_snapshot +/// 5. `[writable, signer]` payer +/// 6. `[]` restaking_program_id +/// 7. `[]` system_program +#[derive(Clone, Debug)] +pub struct InitializeEpochSnapshotCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> InitializeEpochSnapshotCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(InitializeEpochSnapshotCpiBuilderInstruction { + __program: program, + ncn_config: None, + restaking_config: None, + ncn: None, + weight_table: None, + epoch_snapshot: None, + payer: None, + restaking_program_id: None, + system_program: None, + first_slot_of_ncn_epoch: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn ncn_config( + &mut self, + ncn_config: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.ncn_config = Some(ncn_config); + self + } + #[inline(always)] + pub fn restaking_config( + &mut self, + restaking_config: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.restaking_config = Some(restaking_config); + self + } + #[inline(always)] + pub fn ncn(&mut self, ncn: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.ncn = Some(ncn); + self + } + #[inline(always)] + pub fn weight_table( + &mut self, + weight_table: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.weight_table = Some(weight_table); + self + } + #[inline(always)] + pub fn epoch_snapshot( + &mut self, + epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.epoch_snapshot = Some(epoch_snapshot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn restaking_program_id( + &mut self, + restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.restaking_program_id = Some(restaking_program_id); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn first_slot_of_ncn_epoch(&mut self, first_slot_of_ncn_epoch: u64) -> &mut Self { + self.instruction.first_slot_of_ncn_epoch = Some(first_slot_of_ncn_epoch); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = InitializeEpochSnapshotInstructionArgs { + first_slot_of_ncn_epoch: self.instruction.first_slot_of_ncn_epoch.clone(), + }; + let instruction = InitializeEpochSnapshotCpi { + __program: self.instruction.__program, + + ncn_config: self.instruction.ncn_config.expect("ncn_config is not set"), + + restaking_config: self + .instruction + .restaking_config + .expect("restaking_config is not set"), + + ncn: self.instruction.ncn.expect("ncn is not set"), + + weight_table: self + .instruction + .weight_table + .expect("weight_table is not set"), + + epoch_snapshot: self + .instruction + .epoch_snapshot + .expect("epoch_snapshot is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + restaking_program_id: self + .instruction + .restaking_program_id + .expect("restaking_program_id is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct InitializeEpochSnapshotCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + ncn_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ncn: Option<&'b solana_program::account_info::AccountInfo<'a>>, + weight_table: Option<&'b solana_program::account_info::AccountInfo<'a>>, + epoch_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + first_slot_of_ncn_epoch: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/jito_tip_router/src/generated/instructions/mod.rs b/clients/rust/jito_tip_router/src/generated/instructions/mod.rs index 271bac3..076a221 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/mod.rs @@ -5,12 +5,13 @@ //! pub(crate) mod r#admin_update_weight_table; +pub(crate) mod r#initialize_epoch_snapshot; pub(crate) mod r#initialize_n_c_n_config; pub(crate) mod r#initialize_weight_table; pub(crate) mod r#set_config_fees; pub(crate) mod r#set_new_admin; pub use self::{ - r#admin_update_weight_table::*, r#initialize_n_c_n_config::*, r#initialize_weight_table::*, - r#set_config_fees::*, r#set_new_admin::*, + r#admin_update_weight_table::*, r#initialize_epoch_snapshot::*, r#initialize_n_c_n_config::*, + r#initialize_weight_table::*, r#set_config_fees::*, r#set_new_admin::*, }; diff --git a/clients/rust/jito_tip_router/src/generated/types/mod.rs b/clients/rust/jito_tip_router/src/generated/types/mod.rs index ea35df8..1940263 100644 --- a/clients/rust/jito_tip_router/src/generated/types/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/types/mod.rs @@ -7,6 +7,10 @@ pub(crate) mod r#config_admin_role; pub(crate) mod r#fee; pub(crate) mod r#fees; +pub(crate) mod r#vault_operator_delegation_snapshot; pub(crate) mod r#weight_entry; -pub use self::{r#config_admin_role::*, r#fee::*, r#fees::*, r#weight_entry::*}; +pub use self::{ + r#config_admin_role::*, r#fee::*, r#fees::*, r#vault_operator_delegation_snapshot::*, + r#weight_entry::*, +}; diff --git a/clients/rust/jito_tip_router/src/generated/types/vault_operator_delegation_snapshot.rs b/clients/rust/jito_tip_router/src/generated/types/vault_operator_delegation_snapshot.rs new file mode 100644 index 0000000..1b4099d --- /dev/null +++ b/clients/rust/jito_tip_router/src/generated/types/vault_operator_delegation_snapshot.rs @@ -0,0 +1,28 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! + +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct VaultOperatorDelegationSnapshot { + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub vault: Pubkey, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub st_mint: Pubkey, + pub total_security: u64, + pub total_votes: u128, + pub slot_set: u64, + #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] + pub reserved: [u8; 128], +} diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index 7de3e24..2e7f32a 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -1,13 +1,16 @@ use bytemuck::{Pod, Zeroable}; use jito_bytemuck::{ - types::{PodU128, PodU16, PodU64}, + types::{PodBool, PodU128, PodU16, PodU64}, AccountDeserialize, Discriminator, }; use jito_vault_core::delegation_state::DelegationState; use shank::{ShankAccount, ShankType}; -use solana_program::pubkey::Pubkey; +use solana_program::{account_info::AccountInfo, msg, program_error::ProgramError, pubkey::Pubkey}; +use spl_math::precise_number::PreciseNumber; -use crate::{discriminators::Discriminators, fees::Fees}; +use crate::{ + discriminators::Discriminators, error::TipRouterError, fees::Fees, weight_table::WeightTable, +}; // PDA'd ["EPOCH_SNAPSHOT", NCN, NCN_EPOCH_SLOT] #[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] @@ -26,22 +29,100 @@ pub struct EpochSnapshot { /// Bump seed for the PDA bump: u8, - /// Reserved space - reserved: [u8; 128], - ncn_fees: Fees, - num_operators: PodU16, - operators_registered: PodU16, + operator_count: PodU64, + operators_registered: PodU64, /// Counted as each delegate gets added total_votes: PodU128, + + /// Reserved space + reserved: [u8; 128], } impl Discriminator for EpochSnapshot { const DISCRIMINATOR: u8 = Discriminators::EpochSnapshot as u8; } +impl EpochSnapshot { + pub fn new( + ncn: Pubkey, + ncn_epoch: u64, + current_slot: u64, + ncn_fees: Fees, + num_operators: u64, + ) -> Self { + Self { + ncn, + ncn_epoch: PodU64::from(ncn_epoch), + slot_created: PodU64::from(current_slot), + bump: 0, + ncn_fees, + operator_count: PodU64::from(num_operators), + operators_registered: PodU64::from(0), + total_votes: PodU128::from(0), + reserved: [0; 128], + } + } + + pub fn seeds(ncn: &Pubkey, ncn_epoch: u64) -> Vec> { + Vec::from_iter( + [ + b"EPOCH_SNAPSHOT".to_vec(), + ncn.to_bytes().to_vec(), + ncn_epoch.to_le_bytes().to_vec(), + ] + .iter() + .cloned(), + ) + } + + pub fn find_program_address( + program_id: &Pubkey, + ncn: &Pubkey, + ncn_epoch: u64, + ) -> (Pubkey, u8, Vec>) { + let seeds = Self::seeds(ncn, ncn_epoch); + let seeds_iter: Vec<_> = seeds.iter().map(|s| s.as_slice()).collect(); + let (pda, bump) = Pubkey::find_program_address(&seeds_iter, program_id); + (pda, bump, seeds) + } + + pub fn load( + program_id: &Pubkey, + ncn: &Pubkey, + ncn_epoch: u64, + epoch_snapshot: &AccountInfo, + expect_writable: bool, + ) -> Result<(), ProgramError> { + if epoch_snapshot.owner.ne(program_id) { + msg!("Epoch Snapshot account has an invalid owner"); + return Err(ProgramError::InvalidAccountOwner); + } + if epoch_snapshot.data_is_empty() { + msg!("Epoch Snapshot account data is empty"); + return Err(ProgramError::InvalidAccountData); + } + if expect_writable && !epoch_snapshot.is_writable { + msg!("Epoch Snapshot account is not writable"); + return Err(ProgramError::InvalidAccountData); + } + if epoch_snapshot.data.borrow()[0].ne(&Self::DISCRIMINATOR) { + msg!("Epoch Snapshot account discriminator is invalid"); + return Err(ProgramError::InvalidAccountData); + } + if epoch_snapshot + .key + .ne(&Self::find_program_address(program_id, ncn, ncn_epoch).0) + { + msg!("Epoch Snapshot account is not at the correct PDA"); + return Err(ProgramError::InvalidAccountData); + } + Ok(()) + } +} + // PDA'd ["OPERATOR_SNAPSHOT", OPERATOR, NCN, NCN_EPOCH_SLOT] #[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] #[repr(C)] @@ -53,6 +134,8 @@ pub struct OperatorSnapshot { bump: u8, + is_active: PodBool, + operator_fee_bps: PodU16, total_votes: PodU128, @@ -61,22 +144,178 @@ pub struct OperatorSnapshot { vault_operator_delegations_registered: PodU16, slot_set: PodU64, - vault_operator_delegations: [VaultOperatorDelegationSnapshot; 256], + //TODO check upper limit of vaults + vault_operator_delegations: [VaultOperatorDelegationSnapshot; 32], + reserved: [u8; 128], } impl Discriminator for OperatorSnapshot { const DISCRIMINATOR: u8 = Discriminators::OperatorSnapshot as u8; } -// Operators effectively cast N types of votes, -// where N is the number of supported mints +impl OperatorSnapshot { + pub fn new( + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: u64, + is_active: bool, + current_slot: u64, + operator_fee_bps: u16, + ) -> Self { + Self { + operator, + ncn, + ncn_epoch: PodU64::from(ncn_epoch), + slot_created: PodU64::from(0), + bump: 0, + operator_fee_bps: PodU16::from(operator_fee_bps), + total_votes: PodU128::from(0), + is_active: PodBool::from(is_active), + num_vault_operator_delegations: PodU16::from(0), + vault_operator_delegations_registered: PodU16::from(0), + slot_set: PodU64::from(current_slot), + vault_operator_delegations: [VaultOperatorDelegationSnapshot::default(); 32], + reserved: [0; 128], + } + } + + pub fn seeds(operator: &Pubkey, ncn: &Pubkey, ncn_epoch: u64) -> Vec> { + Vec::from_iter( + [ + b"OPERATOR_SNAPSHOT".to_vec(), + operator.to_bytes().to_vec(), + ncn.to_bytes().to_vec(), + ncn_epoch.to_le_bytes().to_vec(), + ] + .iter() + .cloned(), + ) + } + + pub fn find_program_address( + program_id: &Pubkey, + operator: &Pubkey, + ncn: &Pubkey, + ncn_epoch: u64, + ) -> (Pubkey, u8, Vec>) { + let seeds = Self::seeds(operator, ncn, ncn_epoch); + let seeds_iter: Vec<_> = seeds.iter().map(|s| s.as_slice()).collect(); + let (pda, bump) = Pubkey::find_program_address(&seeds_iter, program_id); + (pda, bump, seeds) + } + + pub fn load( + program_id: &Pubkey, + operator: &Pubkey, + ncn: &Pubkey, + ncn_epoch: u64, + operator_snapshot: &AccountInfo, + expect_writable: bool, + ) -> Result<(), ProgramError> { + if operator_snapshot.owner.ne(program_id) { + msg!("Operator Snapshot account has an invalid owner"); + return Err(ProgramError::InvalidAccountOwner); + } + if operator_snapshot.data_is_empty() { + msg!("Operator Snapshot account data is empty"); + return Err(ProgramError::InvalidAccountData); + } + if expect_writable && !operator_snapshot.is_writable { + msg!("Operator Snapshot account is not writable"); + return Err(ProgramError::InvalidAccountData); + } + if operator_snapshot.data.borrow()[0].ne(&Self::DISCRIMINATOR) { + msg!("Operator Snapshot account discriminator is invalid"); + return Err(ProgramError::InvalidAccountData); + } + if operator_snapshot + .key + .ne(&Self::find_program_address(program_id, operator, ncn, ncn_epoch).0) + { + msg!("Operator Snapshot account is not at the correct PDA"); + return Err(ProgramError::InvalidAccountData); + } + Ok(()) + } +} + #[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod)] #[repr(C)] pub struct VaultOperatorDelegationSnapshot { vault: Pubkey, st_mint: Pubkey, - delegation_state: DelegationState, + total_security: PodU64, total_votes: PodU128, slot_set: PodU64, reserved: [u8; 128], } + +impl Default for VaultOperatorDelegationSnapshot { + fn default() -> Self { + Self { + vault: Pubkey::default(), + st_mint: Pubkey::default(), + total_security: PodU64::from(0), + total_votes: PodU128::from(0), + slot_set: PodU64::from(0), + reserved: [0; 128], + } + } +} + +impl VaultOperatorDelegationSnapshot { + pub fn new( + vault: Pubkey, + st_mint: Pubkey, + total_security: u64, + total_votes: u128, + current_slot: u64, + ) -> Self { + Self { + vault, + st_mint, + total_security: PodU64::from(total_security), + total_votes: PodU128::from(total_votes), + slot_set: PodU64::from(current_slot), + reserved: [0; 128], + } + } + + pub fn create_snapshot( + vault: Pubkey, + st_mint: Pubkey, + delegation_state: &DelegationState, + weight_table: &WeightTable, + current_slot: u64, + ) -> Result { + let total_security = delegation_state.total_security()?; + let precise_total_security = PreciseNumber::new(total_security as u128) + .ok_or(TipRouterError::NewPreciseNumberError)?; + + let precise_weight = weight_table.get_precise_weight(&st_mint)?; + + let precise_total_votes = precise_total_security + .checked_mul(&precise_weight) + .ok_or(TipRouterError::ArithmeticOverflow)?; + + let total_votes = precise_total_votes + .to_imprecise() + .ok_or(TipRouterError::CastToImpreciseNumberError)?; + + Ok(Self::new( + vault, + st_mint, + total_security, + total_votes, + current_slot, + )) + } + + pub fn is_empty(&self) -> bool { + self.slot_set.eq(&PodU64::from(0)) + } + + pub fn total_votes(&self) -> u128 { + self.total_votes.into() + } +} diff --git a/core/src/error.rs b/core/src/error.rs index 21fe13a..6f4b6b7 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -33,13 +33,17 @@ pub enum TipRouterError { #[error("Invalid mint for weight table")] InvalidMintForWeightTable, #[error("Fee cap exceeded")] - FeeCapExceeded = 0x2300, + FeeCapExceeded, #[error("Incorrect NCN Admin")] - IncorrectNcnAdmin = 0x2400, + IncorrectNcnAdmin, #[error("Incorrect NCN")] - IncorrectNcn = 0x2401, + IncorrectNcn, #[error("Incorrect fee admin")] - IncorrectFeeAdmin = 0x2402, + IncorrectFeeAdmin, + #[error("Weight table not finalized")] + WeightTableNotFinalized, + #[error("Weight not found")] + WeightNotFound, } impl DecodeError for TipRouterError { diff --git a/core/src/instruction.rs b/core/src/instruction.rs index 169247a..55210dd 100644 --- a/core/src/instruction.rs +++ b/core/src/instruction.rs @@ -10,7 +10,7 @@ pub enum ConfigAdminRole { #[rustfmt::skip] #[derive(Debug, BorshSerialize, BorshDeserialize, ShankInstruction)] -pub enum WeightTableInstruction { +pub enum TipRouterInstruction { /// Initialize the global configuration for this NCN @@ -73,4 +73,32 @@ pub enum WeightTableInstruction { ncn_epoch: u64, weight: u128, }, + + /// Initializes the Epoch Snapshot + #[account(0, name = "ncn_config")] + #[account(1, name = "restaking_config")] + #[account(2, name = "ncn")] + #[account(3, name = "weight_table")] + #[account(4, writable, name = "epoch_snapshot")] + #[account(5, writable, signer, name = "payer")] + #[account(6, name = "restaking_program_id")] + #[account(7, name = "system_program")] + InitializeEpochSnapshot{ + first_slot_of_ncn_epoch: Option, + }, + + /// Initializes the Operator Snapshot + #[account(0, name = "ncn_config")] + #[account(1, name = "restaking_config")] + #[account(2, name = "ncn")] + #[account(3, name = "operator")] + #[account(4, name = "ncn_operator_state")] + #[account(5, writable, name = "epoch_snapshot")] + #[account(6, writable, name = "operator_snapshot")] + #[account(7, writable, signer, name = "payer")] + #[account(8, name = "restaking_program_id")] + #[account(9, name = "system_program")] + InitializeOperatorSnapshot{ + first_slot_of_ncn_epoch: Option, + }, } diff --git a/core/src/lib.rs b/core/src/lib.rs index f90a556..edac4ea 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -4,6 +4,7 @@ pub mod epoch_snapshot; pub mod error; pub mod fees; pub mod instruction; +pub mod loaders; pub mod ncn_config; pub mod weight_entry; pub mod weight_table; diff --git a/core/src/loaders.rs b/core/src/loaders.rs new file mode 100644 index 0000000..8d4f9a3 --- /dev/null +++ b/core/src/loaders.rs @@ -0,0 +1,33 @@ +use jito_bytemuck::AccountDeserialize; +use jito_restaking_core::config::Config; +use solana_program::{account_info::AccountInfo, msg, program_error::ProgramError}; + +use crate::error::TipRouterError; + +pub fn load_ncn_epoch( + restaking_config: &AccountInfo, + current_slot: u64, + first_slot_of_ncn_epoch: Option, +) -> Result<(u64, u64), ProgramError> { + let ncn_epoch_length = { + let config_data = restaking_config.data.borrow(); + let config = Config::try_from_slice_unchecked(&config_data)?; + config.epoch_length() + }; + + let current_ncn_epoch = current_slot + .checked_div(ncn_epoch_length) + .ok_or(TipRouterError::DenominatorIsZero)?; + + let ncn_epoch_slot = first_slot_of_ncn_epoch.unwrap_or(current_slot); + let ncn_epoch = ncn_epoch_slot + .checked_div(ncn_epoch_length) + .ok_or(TipRouterError::DenominatorIsZero)?; + + if ncn_epoch > current_ncn_epoch { + msg!("Epoch snapshots can only be initialized for current or past epochs"); + return Err(TipRouterError::CannotCreateFutureWeightTables.into()); + } + + Ok((ncn_epoch, ncn_epoch_length)) +} diff --git a/core/src/weight_table.rs b/core/src/weight_table.rs index 8ec499a..1d907f2 100644 --- a/core/src/weight_table.rs +++ b/core/src/weight_table.rs @@ -4,6 +4,7 @@ use bytemuck::{Pod, Zeroable}; use jito_bytemuck::{types::PodU64, AccountDeserialize, Discriminator}; use shank::{ShankAccount, ShankType}; use solana_program::{account_info::AccountInfo, msg, program_error::ProgramError, pubkey::Pubkey}; +use spl_math::precise_number::PreciseNumber; use crate::{discriminators::Discriminators, error::TipRouterError, weight_entry::WeightEntry}; @@ -134,6 +135,11 @@ impl WeightTable { }) } + pub fn get_precise_weight(&self, mint: &Pubkey) -> Result { + let weight = self.get_weight(mint)?; + PreciseNumber::new(weight).ok_or(TipRouterError::NewPreciseNumberError) + } + pub fn get_mints(&self) -> Vec { self.table .iter() @@ -142,13 +148,6 @@ impl WeightTable { .collect() } - pub fn find_weight(&self, mint: &Pubkey) -> Option { - self.table - .iter() - .find(|entry| entry.mint() == *mint) - .map(|entry| entry.weight()) - } - pub fn mint_count(&self) -> usize { self.table.iter().filter(|entry| !entry.is_empty()).count() } diff --git a/idl/jito_tip_router.json b/idl/jito_tip_router.json index 3fd2c53..b7d32e8 100644 --- a/idl/jito_tip_router.json +++ b/idl/jito_tip_router.json @@ -262,9 +262,209 @@ "type": "u8", "value": 4 } + }, + { + "name": "InitializeEpochSnapshot", + "accounts": [ + { + "name": "ncnConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "restakingConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "ncn", + "isMut": false, + "isSigner": false + }, + { + "name": "weightTable", + "isMut": false, + "isSigner": false + }, + { + "name": "epochSnapshot", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "restakingProgramId", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "firstSlotOfNcnEpoch", + "type": { + "option": "u64" + } + } + ], + "discriminant": { + "type": "u8", + "value": 5 + } } ], "accounts": [ + { + "name": "EpochSnapshot", + "type": { + "kind": "struct", + "fields": [ + { + "name": "ncn", + "type": "publicKey" + }, + { + "name": "ncnEpoch", + "type": { + "defined": "PodU64" + } + }, + { + "name": "slotCreated", + "type": { + "defined": "PodU64" + } + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "ncnFees", + "type": { + "defined": "Fees" + } + }, + { + "name": "operatorCount", + "type": { + "defined": "PodU64" + } + }, + { + "name": "operatorsRegistered", + "type": { + "defined": "PodU64" + } + }, + { + "name": "totalVotes", + "type": { + "defined": "PodU128" + } + }, + { + "name": "reserved", + "type": { + "array": [ + "u8", + 128 + ] + } + } + ] + } + }, + { + "name": "OperatorSnapshot", + "type": { + "kind": "struct", + "fields": [ + { + "name": "operator", + "type": "publicKey" + }, + { + "name": "ncn", + "type": "publicKey" + }, + { + "name": "ncnEpoch", + "type": { + "defined": "PodU64" + } + }, + { + "name": "slotCreated", + "type": { + "defined": "PodU64" + } + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "operatorFeeBps", + "type": { + "defined": "PodU16" + } + }, + { + "name": "totalVotes", + "type": { + "defined": "PodU128" + } + }, + { + "name": "numVaultOperatorDelegations", + "type": { + "defined": "PodU16" + } + }, + { + "name": "vaultOperatorDelegationsRegistered", + "type": { + "defined": "PodU16" + } + }, + { + "name": "slotSet", + "type": { + "defined": "PodU64" + } + }, + { + "name": "vaultOperatorDelegations", + "type": { + "array": [ + { + "defined": "VaultOperatorDelegationSnapshot" + }, + 32 + ] + } + }, + { + "name": "reserved", + "type": { + "array": [ + "u8", + 128 + ] + } + } + ] + } + }, { "name": "NcnConfig", "type": { @@ -354,6 +554,49 @@ } ], "types": [ + { + "name": "VaultOperatorDelegationSnapshot", + "type": { + "kind": "struct", + "fields": [ + { + "name": "vault", + "type": "publicKey" + }, + { + "name": "stMint", + "type": "publicKey" + }, + { + "name": "totalSecurity", + "type": { + "defined": "PodU64" + } + }, + { + "name": "totalVotes", + "type": { + "defined": "PodU128" + } + }, + { + "name": "slotSet", + "type": { + "defined": "PodU64" + } + }, + { + "name": "reserved", + "type": { + "array": [ + "u8", + 128 + ] + } + } + ] + } + }, { "name": "Fees", "type": { @@ -536,24 +779,34 @@ "msg": "Invalid mint for weight table" }, { - "code": 8960, + "code": 8713, "name": "FeeCapExceeded", "msg": "Fee cap exceeded" }, { - "code": 9216, + "code": 8714, "name": "IncorrectNcnAdmin", "msg": "Incorrect NCN Admin" }, { - "code": 9217, + "code": 8715, "name": "IncorrectNcn", "msg": "Incorrect NCN" }, { - "code": 9218, + "code": 8716, "name": "IncorrectFeeAdmin", "msg": "Incorrect fee admin" + }, + { + "code": 8717, + "name": "WeightTableNotFinalized", + "msg": "Weight table not finalized" + }, + { + "code": 8718, + "name": "WeightNotFound", + "msg": "Weight not found" } ], "metadata": { diff --git a/integration_tests/tests/fixtures/tip_router_client.rs b/integration_tests/tests/fixtures/tip_router_client.rs index ce14f56..ec3a09d 100644 --- a/integration_tests/tests/fixtures/tip_router_client.rs +++ b/integration_tests/tests/fixtures/tip_router_client.rs @@ -2,13 +2,14 @@ use jito_bytemuck::AccountDeserialize; use jito_restaking_core::config::Config; use jito_tip_router_client::{ instructions::{ - AdminUpdateWeightTableBuilder, InitializeNCNConfigBuilder, InitializeWeightTableBuilder, - SetConfigFeesBuilder, SetNewAdminBuilder, + AdminUpdateWeightTableBuilder, InitializeEpochSnapshotBuilder, InitializeNCNConfigBuilder, + InitializeWeightTableBuilder, SetConfigFeesBuilder, SetNewAdminBuilder, }, types::ConfigAdminRole, }; use jito_tip_router_core::{ - error::TipRouterError, ncn_config::NcnConfig, weight_table::WeightTable, + epoch_snapshot::EpochSnapshot, error::TipRouterError, ncn_config::NcnConfig, + weight_table::WeightTable, }; use solana_program::{ instruction::InstructionError, native_token::sol_to_lamports, pubkey::Pubkey, @@ -307,6 +308,52 @@ impl TipRouterClient { )) .await } + + pub async fn do_initialize_epoch_snapshot( + &mut self, + ncn: Pubkey, + current_slot: u64, + ) -> TestResult<()> { + self.initialize_epoch_snapshot(ncn, current_slot).await + } + + pub async fn initialize_epoch_snapshot( + &mut self, + ncn: Pubkey, + current_slot: u64, + ) -> TestResult<()> { + let restaking_config = Config::find_program_address(&jito_restaking_program::id()).0; + + let restaking_config_account = self.get_restaking_config().await?; + let ncn_epoch = current_slot / restaking_config_account.epoch_length(); + + let config_pda = NcnConfig::find_program_address(&jito_tip_router_program::id(), &ncn).0; + let weight_table = + WeightTable::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; + + let epoch_snapshot = + EpochSnapshot::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; + + let ix = InitializeEpochSnapshotBuilder::new() + .restaking_config(restaking_config) + .ncn_config(config_pda) + .ncn(ncn) + .weight_table(weight_table) + .epoch_snapshot(epoch_snapshot) + .payer(self.payer.pubkey()) + .restaking_program_id(jito_restaking_program::id()) + .system_program(system_program::id()) + .instruction(); + + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.process_transaction(&Transaction::new_signed_with_payer( + &[ix], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + )) + .await + } } #[inline(always)] diff --git a/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs b/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs new file mode 100644 index 0000000..74708cc --- /dev/null +++ b/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs @@ -0,0 +1,33 @@ +#[cfg(test)] +mod tests { + + use crate::fixtures::{test_builder::TestBuilder, TestResult}; + + #[tokio::test] + async fn test_initialize_epoch_snapshot_ok() -> TestResult<()> { + let mut fixture = TestBuilder::new().await; + let mut tip_router_client = fixture.tip_router_client(); + let ncn_root = fixture.setup_ncn().await?; + + fixture.warp_slot_incremental(1000).await?; + + let slot = fixture.clock().await.slot; + + //TODO fix when config has mints + tip_router_client + .do_initialize_config(ncn_root.ncn_pubkey, &ncn_root.ncn_admin) + .await?; + + tip_router_client + .do_initialize_weight_table(ncn_root.ncn_pubkey, slot) + .await?; + + //TODO update table + + tip_router_client + .do_initialize_epoch_snapshot(ncn_root.ncn_pubkey, slot) + .await?; + + Ok(()) + } +} diff --git a/integration_tests/tests/tip_router/mod.rs b/integration_tests/tests/tip_router/mod.rs index dd9a5a4..1beecdc 100644 --- a/integration_tests/tests/tip_router/mod.rs +++ b/integration_tests/tests/tip_router/mod.rs @@ -1,4 +1,5 @@ mod admin_update_weight_table; +mod initialize_epoch_snapshot; mod initialize_ncn_config; mod initialize_weight_table; mod set_config_fees; diff --git a/program/src/finalize_weight_table.rs b/program/src/finalize_weight_table.rs deleted file mode 100644 index 76583c0..0000000 --- a/program/src/finalize_weight_table.rs +++ /dev/null @@ -1,51 +0,0 @@ -use jito_bytemuck::AccountDeserialize; -use jito_jsm_core::loader::load_signer; -use jito_restaking_core::ncn::Ncn; -use jito_tip_router_core::{error::TipRouterError, weight_table::WeightTable}; -use solana_program::{ - account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, - program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar, -}; - -/// Initializes a Weight Table -pub fn process_finalize_weight_table( - program_id: &Pubkey, - accounts: &[AccountInfo], - ncn_epoch: u64, - mint_hash: u64, - mint_count: u8, -) -> ProgramResult { - let [ncn, weight_table, weight_table_admin, restaking_program_id] = accounts else { - return Err(ProgramError::NotEnoughAccountKeys); - }; - - Ncn::load(restaking_program_id.key, ncn, false)?; - let ncn_weight_table_admin = { - let ncn_data = ncn.data.borrow(); - let ncn = Ncn::try_from_slice_unchecked(&ncn_data)?; - ncn.weight_table_admin - }; - - load_signer(weight_table_admin, true)?; - WeightTable::load(program_id, weight_table, ncn, ncn_epoch, true)?; - - if restaking_program_id.key.ne(&jito_restaking_program::id()) { - msg!("Incorrect restaking program ID"); - return Err(ProgramError::InvalidAccountData); - } - - if ncn_weight_table_admin.ne(weight_table_admin.key) { - msg!("Vault update delegations ticket is not at the correct PDA"); - return Err(TipRouterError::IncorrectWeightTableAdmin.into()); - } - - let mut weight_table_data = weight_table.try_borrow_mut_data()?; - let weight_table_account = WeightTable::try_from_slice_unchecked_mut(&mut weight_table_data)?; - - weight_table_account.check_mints_okay(mint_hash, mint_count)?; - - let current_slot = Clock::get()?.slot; - weight_table_account.finalize(current_slot); - - Ok(()) -} diff --git a/program/src/initialize_epoch_snapshot.rs b/program/src/initialize_epoch_snapshot.rs new file mode 100644 index 0000000..b525d1c --- /dev/null +++ b/program/src/initialize_epoch_snapshot.rs @@ -0,0 +1,107 @@ +use jito_bytemuck::{AccountDeserialize, Discriminator}; +use jito_jsm_core::{ + create_account, + loader::{load_signer, load_system_account, load_system_program}, +}; +use jito_restaking_core::{config::Config, ncn::Ncn}; +use jito_tip_router_core::{ + epoch_snapshot::EpochSnapshot, error::TipRouterError, fees, loaders::load_ncn_epoch, + ncn_config::NcnConfig, weight_table::WeightTable, +}; +use solana_program::{ + account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, + program_error::ProgramError, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, +}; + +/// Initializes an Epoch Snapshot +pub fn process_initialize_epoch_snapshot( + program_id: &Pubkey, + accounts: &[AccountInfo], + first_slot_of_ncn_epoch: Option, +) -> ProgramResult { + let [ncn_config, restaking_config, ncn, weight_table, epoch_snapshot, payer, restaking_program_id, system_program] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if restaking_program_id.key.ne(&jito_restaking_program::id()) { + msg!("Incorrect restaking program ID"); + return Err(ProgramError::InvalidAccountData); + } + + NcnConfig::load(program_id, ncn.key, ncn_config, false)?; + Config::load(restaking_program_id.key, restaking_config, false)?; + Ncn::load(restaking_program_id.key, ncn, false)?; + + load_system_account(epoch_snapshot, true)?; + load_system_program(system_program)?; + //TODO check that it is not writable + load_signer(payer, false)?; + + let current_slot = Clock::get()?.slot; + let (ncn_epoch, _) = load_ncn_epoch(restaking_config, current_slot, first_slot_of_ncn_epoch)?; + + WeightTable::load(program_id, weight_table, ncn, ncn_epoch, false)?; + + // Weight table needs to be finalized before the snapshot can be taken + { + let weight_table_data = weight_table.data.borrow(); + let weight_table_account = WeightTable::try_from_slice_unchecked(&weight_table_data)?; + + if !weight_table_account.finalized() { + msg!("Weight table must be finalized before initializing epoch snapshot"); + return Err(TipRouterError::WeightTableNotFinalized.into()); + } + } + + let (epoch_snapshot_pubkey, epoch_snapshot_bump, mut epoch_snapshot_seeds) = + EpochSnapshot::find_program_address(program_id, ncn.key, ncn_epoch); + epoch_snapshot_seeds.push(vec![epoch_snapshot_bump]); + + if epoch_snapshot_pubkey.ne(epoch_snapshot.key) { + msg!("Incorrect epoch snapshot PDA"); + return Err(ProgramError::InvalidAccountData); + } + + msg!( + "Initializing Epoch snapshot {} for NCN: {} at epoch: {}", + epoch_snapshot.key, + ncn.key, + ncn_epoch + ); + create_account( + payer, + epoch_snapshot, + system_program, + program_id, + &Rent::get()?, + 8_u64 + .checked_add(std::mem::size_of::() as u64) + .unwrap(), + &epoch_snapshot_seeds, + )?; + + let ncn_fees: fees::Fees = { + let ncn_config_data = ncn_config.data.borrow(); + let ncn_config_account = NcnConfig::try_from_slice_unchecked(&ncn_config_data)?; + ncn_config_account.fees + }; + + let operator_count: u64 = { + let ncn_data = ncn.data.borrow(); + let ncn_account = Ncn::try_from_slice_unchecked(&ncn_data)?; + ncn_account.operator_count() + }; + + let mut epoch_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = + epoch_snapshot.try_borrow_mut_data()?; + epoch_snapshot_data[0] = EpochSnapshot::DISCRIMINATOR; + let epoch_snapshot_account = + EpochSnapshot::try_from_slice_unchecked_mut(&mut epoch_snapshot_data)?; + + *epoch_snapshot_account = + EpochSnapshot::new(*ncn.key, ncn_epoch, current_slot, ncn_fees, operator_count); + + Ok(()) +} diff --git a/program/src/initialize_operator_snapshot.rs b/program/src/initialize_operator_snapshot.rs new file mode 100644 index 0000000..cf41f31 --- /dev/null +++ b/program/src/initialize_operator_snapshot.rs @@ -0,0 +1,124 @@ +use jito_bytemuck::{AccountDeserialize, Discriminator}; +use jito_jsm_core::{ + create_account, + loader::{load_signer, load_system_account, load_system_program}, +}; +use jito_restaking_core::{ + config::Config, ncn::Ncn, ncn_operator_state::NcnOperatorState, operator::Operator, +}; +use jito_tip_router_core::{ + epoch_snapshot::{EpochSnapshot, OperatorSnapshot}, + error::TipRouterError, + fees, + loaders::load_ncn_epoch, + ncn_config::NcnConfig, + weight_table::WeightTable, +}; +use solana_program::{ + account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, + program_error::ProgramError, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, +}; + +/// Initializes an Operator Snapshot +pub fn process_initialize_operator_snapshot( + program_id: &Pubkey, + accounts: &[AccountInfo], + first_slot_of_ncn_epoch: Option, +) -> ProgramResult { + let [ncn_config, restaking_config, ncn, operator, ncn_operator_state, epoch_snapshot, operator_snapshot, payer, restaking_program_id, system_program] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if restaking_program_id.key.ne(&jito_restaking_program::id()) { + msg!("Incorrect restaking program ID"); + return Err(ProgramError::InvalidAccountData); + } + + NcnConfig::load(program_id, ncn.key, ncn_config, false)?; + Config::load(restaking_program_id.key, restaking_config, false)?; + Ncn::load(restaking_program_id.key, ncn, false)?; + Operator::load(restaking_program_id.key, operator, false)?; + NcnOperatorState::load( + restaking_program_id.key, + ncn_operator_state, + ncn, + operator, + false, + )?; + + load_system_account(epoch_snapshot, true)?; + load_system_program(system_program)?; + //TODO check that it is not writable + load_signer(payer, false)?; + + let current_slot = Clock::get()?.slot; + let (ncn_epoch, ncn_epoch_length) = + load_ncn_epoch(restaking_config, current_slot, first_slot_of_ncn_epoch)?; + + EpochSnapshot::load(program_id, ncn.key, ncn_epoch, epoch_snapshot, true)?; + + let is_active: bool = { + let ncn_operator_state_data = ncn_operator_state.data.borrow(); + let ncn_operator_state_account = + NcnOperatorState::try_from_slice_unchecked(&ncn_operator_state_data)?; + + ncn_operator_state_account + .ncn_opt_in_state + .is_active(current_slot, ncn_epoch_length) + && ncn_operator_state_account + .operator_opt_in_state + .is_active(current_slot, ncn_epoch_length) + }; + + let (operator_snapshot_pubkey, operator_snapshot_bump, mut operator_snapshot_seeds) = + EpochSnapshot::find_program_address(program_id, ncn.key, ncn_epoch); + operator_snapshot_seeds.push(vec![operator_snapshot_bump]); + + if operator_snapshot_pubkey.ne(operator_snapshot.key) { + msg!("Incorrect epoch snapshot PDA"); + return Err(ProgramError::InvalidAccountData); + } + + msg!( + "Initializing Operator snapshot {} for NCN: {} at epoch: {}", + epoch_snapshot.key, + ncn.key, + ncn_epoch + ); + create_account( + payer, + operator_snapshot, + system_program, + program_id, + &Rent::get()?, + 8_u64 + .checked_add(std::mem::size_of::() as u64) + .unwrap(), + &operator_snapshot_seeds, + )?; + + let ncn_fees: fees::Fees = { + let ncn_config_data = ncn_config.data.borrow(); + let ncn_config_account = NcnConfig::try_from_slice_unchecked(&ncn_config_data)?; + ncn_config_account.fees + }; + + let operator_count: u64 = { + let ncn_data = ncn.data.borrow(); + let ncn_account = Ncn::try_from_slice_unchecked(&ncn_data)?; + ncn_account.operator_count() + }; + + let mut operator_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = + operator_snapshot.try_borrow_mut_data()?; + operator_snapshot_data[0] = EpochSnapshot::DISCRIMINATOR; + let operator_snapshot_account = + OperatorSnapshot::try_from_slice_unchecked_mut(&mut operator_snapshot_data)?; + + *operator_snapshot_account = + OperatorSnapshot::new(*ncn.key, ncn_epoch, current_slot, ncn_fees, operator_count); + + Ok(()) +} diff --git a/program/src/initialize_weight_table.rs b/program/src/initialize_weight_table.rs index 9ef5ef4..1895f24 100644 --- a/program/src/initialize_weight_table.rs +++ b/program/src/initialize_weight_table.rs @@ -5,9 +5,10 @@ use jito_jsm_core::{ create_account, loader::{load_signer, load_system_account, load_system_program}, }; -use jito_restaking_core::config::Config; +use jito_restaking_core::{config::Config, ncn::Ncn}; use jito_tip_router_core::{ - error::TipRouterError, ncn_config::NcnConfig, weight_table::WeightTable, + error::TipRouterError, loaders::load_ncn_epoch, ncn_config::NcnConfig, + weight_table::WeightTable, }; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, @@ -27,44 +28,27 @@ pub fn process_initialize_weight_table( return Err(ProgramError::NotEnoughAccountKeys); }; + if restaking_program_id.key.ne(&jito_restaking_program::id()) { + msg!("Incorrect restaking program ID"); + return Err(ProgramError::InvalidAccountData); + } + NcnConfig::load(program_id, ncn.key, ncn_config, false)?; Config::load(restaking_program_id.key, restaking_config, false)?; - - let ncn_epoch_length = { - let config_data = restaking_config.data.borrow(); - let config = Config::try_from_slice_unchecked(&config_data)?; - config.epoch_length() - }; - - let _todo_pubkeys = { - let ncn_config_data = ncn_config.data.borrow(); - let ncn_config = NcnConfig::try_from_slice_unchecked(&ncn_config_data)?; - ncn_config.bump - }; + Ncn::load(restaking_program_id.key, ncn, false)?; load_system_account(weight_table, true)?; load_system_program(system_program)?; load_signer(payer, true)?; - if restaking_program_id.key.ne(&jito_restaking_program::id()) { - msg!("Incorrect restaking program ID"); - return Err(ProgramError::InvalidAccountData); - } - let current_slot = Clock::get()?.slot; - let current_ncn_epoch = current_slot - .checked_div(ncn_epoch_length) - .ok_or(TipRouterError::DenominatorIsZero)?; - - let ncn_epoch_slot = first_slot_of_ncn_epoch.unwrap_or(current_slot); - let ncn_epoch = ncn_epoch_slot - .checked_div(ncn_epoch_length) - .ok_or(TipRouterError::DenominatorIsZero)?; + let (ncn_epoch, _) = load_ncn_epoch(restaking_config, current_slot, first_slot_of_ncn_epoch)?; - if ncn_epoch > current_ncn_epoch { - msg!("Weight tables can only be initialized for current or past epochs"); - return Err(TipRouterError::CannotCreateFutureWeightTables.into()); - } + let _todo_pubkeys = { + let ncn_config_data = ncn_config.data.borrow(); + let ncn_config = NcnConfig::try_from_slice_unchecked(&ncn_config_data)?; + ncn_config.bump + }; let (weight_table_pubkey, weight_table_bump, mut weight_table_seeds) = WeightTable::find_program_address(program_id, ncn.key, ncn_epoch); diff --git a/program/src/lib.rs b/program/src/lib.rs index 77761aa..6b2e4c6 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -1,12 +1,14 @@ mod admin_update_weight_table; +mod initialize_epoch_snapshot; mod initialize_ncn_config; +mod initialize_operator_snapshot; mod initialize_weight_table; mod set_config_fees; mod set_new_admin; use borsh::BorshDeserialize; use const_str_to_pubkey::str_to_pubkey; -use jito_tip_router_core::instruction::WeightTableInstruction; +use jito_tip_router_core::instruction::TipRouterInstruction; use set_new_admin::process_set_new_admin; use solana_program::{ account_info::AccountInfo, declare_id, entrypoint::ProgramResult, msg, @@ -17,7 +19,9 @@ use solana_security_txt::security_txt; use crate::{ admin_update_weight_table::process_admin_update_weight_table, + initialize_epoch_snapshot::process_initialize_epoch_snapshot, initialize_ncn_config::process_initialize_ncn_config, + initialize_operator_snapshot::process_initialize_operator_snapshot, initialize_weight_table::process_initialize_weight_table, set_config_fees::process_set_config_fees, }; @@ -48,13 +52,13 @@ pub fn process_instruction( return Err(ProgramError::IncorrectProgramId); } - let instruction = WeightTableInstruction::try_from_slice(instruction_data)?; + let instruction = TipRouterInstruction::try_from_slice(instruction_data)?; match instruction { // ------------------------------------------ // Initialization // ------------------------------------------ - WeightTableInstruction::InitializeNCNConfig { + TipRouterInstruction::InitializeNCNConfig { dao_fee_bps, ncn_fee_bps, block_engine_fee_bps, @@ -68,20 +72,32 @@ pub fn process_instruction( block_engine_fee_bps, ) } - WeightTableInstruction::InitializeWeightTable { + TipRouterInstruction::InitializeWeightTable { first_slot_of_ncn_epoch, } => { msg!("Instruction: InitializeWeightTable"); process_initialize_weight_table(program_id, accounts, first_slot_of_ncn_epoch) } + TipRouterInstruction::InitializeEpochSnapshot { + first_slot_of_ncn_epoch, + } => { + msg!("Instruction: InitializeEpochSnapshot"); + process_initialize_epoch_snapshot(program_id, accounts, first_slot_of_ncn_epoch) + } + TipRouterInstruction::InitializeOperatorSnapshot { + first_slot_of_ncn_epoch, + } => { + msg!("Instruction: InitializeOperatorSnapshot"); + process_initialize_operator_snapshot(program_id, accounts, first_slot_of_ncn_epoch) + } // ------------------------------------------ // Update // ------------------------------------------ - WeightTableInstruction::AdminUpdateWeightTable { ncn_epoch, weight } => { + TipRouterInstruction::AdminUpdateWeightTable { ncn_epoch, weight } => { msg!("Instruction: UpdateWeightTable"); process_admin_update_weight_table(program_id, accounts, ncn_epoch, weight) } - WeightTableInstruction::SetConfigFees { + TipRouterInstruction::SetConfigFees { new_dao_fee_bps, new_ncn_fee_bps, new_block_engine_fee_bps, @@ -97,7 +113,7 @@ pub fn process_instruction( new_fee_wallet, ) } - WeightTableInstruction::SetNewAdmin { role } => { + TipRouterInstruction::SetNewAdmin { role } => { msg!("Instruction: SetNewAdmin"); process_set_new_admin(program_id, accounts, role) } From ed04d056afe6cffe7c6f8685a444134b0ea9c531 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Mon, 11 Nov 2024 13:26:37 -0800 Subject: [PATCH 04/28] one more function maybe --- core/src/epoch_snapshot.rs | 129 +++++++++++++++++--- core/src/error.rs | 2 + program/src/initialize_epoch_snapshot.rs | 15 ++- program/src/initialize_operator_snapshot.rs | 50 +++++--- program/src/initialize_weight_table.rs | 3 +- 5 files changed, 162 insertions(+), 37 deletions(-) diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index 2e7f32a..cd3035e 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -23,18 +23,21 @@ pub struct EpochSnapshot { /// The NCN epoch for which the Epoch snapshot is valid ncn_epoch: PodU64, - /// Slot Epoch snapshot was created - slot_created: PodU64, - /// Bump seed for the PDA bump: u8, + /// Slot Epoch snapshot was created + slot_created: PodU64, + slot_finalized: PodU64, + ncn_fees: Fees, operator_count: PodU64, operators_registered: PodU64, + valid_operator_vault_delegations: PodU64, /// Counted as each delegate gets added + ///TODO What happens if `finalized() && total_votes() == 0`? total_votes: PodU128, /// Reserved space @@ -49,6 +52,7 @@ impl EpochSnapshot { pub fn new( ncn: Pubkey, ncn_epoch: u64, + bump: u8, current_slot: u64, ncn_fees: Fees, num_operators: u64, @@ -57,10 +61,12 @@ impl EpochSnapshot { ncn, ncn_epoch: PodU64::from(ncn_epoch), slot_created: PodU64::from(current_slot), - bump: 0, + slot_finalized: PodU64::from(0), + bump, ncn_fees, operator_count: PodU64::from(num_operators), operators_registered: PodU64::from(0), + valid_operator_vault_delegations: PodU64::from(0), total_votes: PodU128::from(0), reserved: [0; 128], } @@ -121,6 +127,57 @@ impl EpochSnapshot { } Ok(()) } + + pub fn operator_count(&self) -> u64 { + self.operator_count.into() + } + + pub fn operators_registered(&self) -> u64 { + self.operators_registered.into() + } + + pub fn valid_operator_vault_delegations(&self) -> u64 { + self.valid_operator_vault_delegations.into() + } + + pub fn total_votes(&self) -> u128 { + self.total_votes.into() + } + + pub fn finalized(&self) -> bool { + self.operators_registered() == self.operator_count() + } + + pub fn increment_operator_registration( + &mut self, + current_slot: u64, + vault_operator_delegations: u64, + votes: u128, + ) -> Result<(), TipRouterError> { + self.operators_registered = PodU64::from( + self.operators_registered() + .checked_add(1) + .ok_or(TipRouterError::ArithmeticOverflow)?, + ); + + self.valid_operator_vault_delegations = PodU64::from( + self.valid_operator_vault_delegations() + .checked_add(vault_operator_delegations) + .ok_or(TipRouterError::ArithmeticOverflow)?, + ); + + self.total_votes = PodU128::from( + self.total_votes() + .checked_add(votes) + .ok_or(TipRouterError::ArithmeticOverflow)?, + ); + + if self.finalized() { + self.slot_finalized = PodU64::from(current_slot); + } + + Ok(()) + } } // PDA'd ["OPERATOR_SNAPSHOT", OPERATOR, NCN, NCN_EPOCH_SLOT] @@ -130,22 +187,22 @@ pub struct OperatorSnapshot { operator: Pubkey, ncn: Pubkey, ncn_epoch: PodU64, - slot_created: PodU64, - bump: u8, + slot_created: PodU64, + slot_finalized: PodU64, + is_active: PodBool, operator_fee_bps: PodU16, - total_votes: PodU128, + vault_operator_delegation_count: PodU64, + vault_operator_delegations_registered: PodU64, - num_vault_operator_delegations: PodU16, - vault_operator_delegations_registered: PodU16, + total_votes: PodU128, - slot_set: PodU64, //TODO check upper limit of vaults - vault_operator_delegations: [VaultOperatorDelegationSnapshot; 32], + vault_operator_delegations: [VaultOperatorDelegationSnapshot; 64], reserved: [u8; 128], } @@ -158,27 +215,63 @@ impl OperatorSnapshot { operator: Pubkey, ncn: Pubkey, ncn_epoch: u64, - is_active: bool, + bump: u8, current_slot: u64, + is_active: bool, operator_fee_bps: u16, + vault_operator_delegation_count: u64, ) -> Self { Self { operator, ncn, ncn_epoch: PodU64::from(ncn_epoch), - slot_created: PodU64::from(0), - bump: 0, + bump, + slot_created: PodU64::from(current_slot), + slot_finalized: PodU64::from(0), operator_fee_bps: PodU16::from(operator_fee_bps), total_votes: PodU128::from(0), is_active: PodBool::from(is_active), - num_vault_operator_delegations: PodU16::from(0), - vault_operator_delegations_registered: PodU16::from(0), - slot_set: PodU64::from(current_slot), - vault_operator_delegations: [VaultOperatorDelegationSnapshot::default(); 32], + vault_operator_delegation_count: PodU64::from(vault_operator_delegation_count), + vault_operator_delegations_registered: PodU64::from(0), + vault_operator_delegations: [VaultOperatorDelegationSnapshot::default(); 64], reserved: [0; 128], } } + pub fn new_active( + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: u64, + bump: u8, + current_slot: u64, + operator_fee_bps: u16, + vault_count: u64, + ) -> Self { + Self::new( + operator, + ncn, + ncn_epoch, + bump, + current_slot, + true, + operator_fee_bps, + vault_count, + ) + } + + pub fn new_inactive( + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: u64, + bump: u8, + current_slot: u64, + ) -> Self { + let mut snapshot = Self::new(operator, ncn, ncn_epoch, bump, current_slot, true, 0, 0); + + snapshot.slot_finalized = PodU64::from(current_slot); + snapshot + } + pub fn seeds(operator: &Pubkey, ncn: &Pubkey, ncn_epoch: u64) -> Vec> { Vec::from_iter( [ diff --git a/core/src/error.rs b/core/src/error.rs index 6f4b6b7..4d6cca0 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -44,6 +44,8 @@ pub enum TipRouterError { WeightTableNotFinalized, #[error("Weight not found")] WeightNotFound, + #[error("No operators in ncn")] + NoOperators, } impl DecodeError for TipRouterError { diff --git a/program/src/initialize_epoch_snapshot.rs b/program/src/initialize_epoch_snapshot.rs index b525d1c..92c2bb4 100644 --- a/program/src/initialize_epoch_snapshot.rs +++ b/program/src/initialize_epoch_snapshot.rs @@ -94,14 +94,25 @@ pub fn process_initialize_epoch_snapshot( ncn_account.operator_count() }; + if operator_count == 0 { + msg!("No operators to snapshot"); + return Err(TipRouterError::NoOperators.into()); + } + let mut epoch_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = epoch_snapshot.try_borrow_mut_data()?; epoch_snapshot_data[0] = EpochSnapshot::DISCRIMINATOR; let epoch_snapshot_account = EpochSnapshot::try_from_slice_unchecked_mut(&mut epoch_snapshot_data)?; - *epoch_snapshot_account = - EpochSnapshot::new(*ncn.key, ncn_epoch, current_slot, ncn_fees, operator_count); + *epoch_snapshot_account = EpochSnapshot::new( + *ncn.key, + ncn_epoch, + epoch_snapshot_bump, + current_slot, + ncn_fees, + operator_count, + ); Ok(()) } diff --git a/program/src/initialize_operator_snapshot.rs b/program/src/initialize_operator_snapshot.rs index cf41f31..398c9d4 100644 --- a/program/src/initialize_operator_snapshot.rs +++ b/program/src/initialize_operator_snapshot.rs @@ -8,11 +8,8 @@ use jito_restaking_core::{ }; use jito_tip_router_core::{ epoch_snapshot::{EpochSnapshot, OperatorSnapshot}, - error::TipRouterError, - fees, loaders::load_ncn_epoch, ncn_config::NcnConfig, - weight_table::WeightTable, }; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, @@ -99,16 +96,13 @@ pub fn process_initialize_operator_snapshot( &operator_snapshot_seeds, )?; - let ncn_fees: fees::Fees = { - let ncn_config_data = ncn_config.data.borrow(); - let ncn_config_account = NcnConfig::try_from_slice_unchecked(&ncn_config_data)?; - ncn_config_account.fees - }; - - let operator_count: u64 = { - let ncn_data = ncn.data.borrow(); - let ncn_account = Ncn::try_from_slice_unchecked(&ncn_data)?; - ncn_account.operator_count() + let (operator_fee_bps, vault_count): (u16, u64) = { + let operator_data = operator.data.borrow(); + let operator_account = Operator::try_from_slice_unchecked(&operator_data)?; + ( + operator_account.operator_fee_bps.into(), + operator_account.vault_count(), + ) }; let mut operator_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = @@ -117,8 +111,34 @@ pub fn process_initialize_operator_snapshot( let operator_snapshot_account = OperatorSnapshot::try_from_slice_unchecked_mut(&mut operator_snapshot_data)?; - *operator_snapshot_account = - OperatorSnapshot::new(*ncn.key, ncn_epoch, current_slot, ncn_fees, operator_count); + *operator_snapshot_account = if is_active { + OperatorSnapshot::new_active( + *operator.key, + *ncn.key, + ncn_epoch, + operator_snapshot_bump, + current_slot, + operator_fee_bps, + vault_count, + ) + } else { + OperatorSnapshot::new_inactive( + *operator.key, + *ncn.key, + ncn_epoch, + operator_snapshot_bump, + current_slot, + ) + }; + + // Increment operator registration for an inactive operator + if !is_active { + let mut epoch_snapshot_data = epoch_snapshot.try_borrow_mut_data()?; + let epoch_snapshot_account = + EpochSnapshot::try_from_slice_unchecked_mut(&mut epoch_snapshot_data)?; + + epoch_snapshot_account.increment_operator_registration(current_slot, 0, 0)?; + } Ok(()) } diff --git a/program/src/initialize_weight_table.rs b/program/src/initialize_weight_table.rs index 1895f24..384a8be 100644 --- a/program/src/initialize_weight_table.rs +++ b/program/src/initialize_weight_table.rs @@ -7,8 +7,7 @@ use jito_jsm_core::{ }; use jito_restaking_core::{config::Config, ncn::Ncn}; use jito_tip_router_core::{ - error::TipRouterError, loaders::load_ncn_epoch, ncn_config::NcnConfig, - weight_table::WeightTable, + loaders::load_ncn_epoch, ncn_config::NcnConfig, weight_table::WeightTable, }; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, From b1dd01e085d1d0178b8fbfcd4b6a4c8296b21717 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Mon, 11 Nov 2024 17:07:25 -0800 Subject: [PATCH 05/28] good work --- core/src/discriminators.rs | 1 + core/src/epoch_snapshot.rs | 229 ++++++++++++++---- core/src/instruction.rs | 20 ++ program/src/initialize_operator_snapshot.rs | 45 ++-- ...lize_vault_operator_delegation_snapshot.rs | 200 +++++++++++++++ program/src/lib.rs | 12 + 6 files changed, 436 insertions(+), 71 deletions(-) create mode 100644 program/src/initialize_vault_operator_delegation_snapshot.rs diff --git a/core/src/discriminators.rs b/core/src/discriminators.rs index 7df10f6..2bfa55d 100644 --- a/core/src/discriminators.rs +++ b/core/src/discriminators.rs @@ -4,4 +4,5 @@ pub enum Discriminators { WeightTable = 2, EpochSnapshot = 3, OperatorSnapshot = 4, + VaultOperatorDelegationSnapshot = 5, } diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index cd3035e..251ad99 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -3,14 +3,10 @@ use jito_bytemuck::{ types::{PodBool, PodU128, PodU16, PodU64}, AccountDeserialize, Discriminator, }; -use jito_vault_core::delegation_state::DelegationState; use shank::{ShankAccount, ShankType}; use solana_program::{account_info::AccountInfo, msg, program_error::ProgramError, pubkey::Pubkey}; -use spl_math::precise_number::PreciseNumber; -use crate::{ - discriminators::Discriminators, error::TipRouterError, fees::Fees, weight_table::WeightTable, -}; +use crate::{discriminators::Discriminators, error::TipRouterError, fees::Fees}; // PDA'd ["EPOCH_SNAPSHOT", NCN, NCN_EPOCH_SLOT] #[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] @@ -198,11 +194,10 @@ pub struct OperatorSnapshot { vault_operator_delegation_count: PodU64, vault_operator_delegations_registered: PodU64, + valid_operator_vault_delegations: PodU64, total_votes: PodU128, - //TODO check upper limit of vaults - vault_operator_delegations: [VaultOperatorDelegationSnapshot; 64], reserved: [u8; 128], } @@ -228,12 +223,12 @@ impl OperatorSnapshot { bump, slot_created: PodU64::from(current_slot), slot_finalized: PodU64::from(0), - operator_fee_bps: PodU16::from(operator_fee_bps), - total_votes: PodU128::from(0), is_active: PodBool::from(is_active), + operator_fee_bps: PodU16::from(operator_fee_bps), vault_operator_delegation_count: PodU64::from(vault_operator_delegation_count), vault_operator_delegations_registered: PodU64::from(0), - vault_operator_delegations: [VaultOperatorDelegationSnapshot::default(); 64], + valid_operator_vault_delegations: PodU64::from(0), + total_votes: PodU128::from(0), reserved: [0; 128], } } @@ -330,85 +325,219 @@ impl OperatorSnapshot { } Ok(()) } + + pub fn vault_operator_delegation_count(&self) -> u64 { + self.vault_operator_delegation_count.into() + } + + pub fn vault_operator_delegations_registered(&self) -> u64 { + self.vault_operator_delegations_registered.into() + } + + pub fn valid_operator_vault_delegations(&self) -> u64 { + self.valid_operator_vault_delegations.into() + } + + pub fn total_votes(&self) -> u128 { + self.total_votes.into() + } + + pub fn finalized(&self) -> bool { + self.vault_operator_delegations_registered() == self.vault_operator_delegation_count() + } + + pub fn increment_vault_operator_delegation_registration( + &mut self, + current_slot: u64, + vault_operator_delegations: u64, + votes: u128, + ) -> Result<(), TipRouterError> { + self.vault_operator_delegations_registered = PodU64::from( + self.vault_operator_delegations_registered() + .checked_add(1) + .ok_or(TipRouterError::ArithmeticOverflow)?, + ); + + self.valid_operator_vault_delegations = PodU64::from( + self.valid_operator_vault_delegations() + .checked_add(vault_operator_delegations) + .ok_or(TipRouterError::ArithmeticOverflow)?, + ); + + self.total_votes = PodU128::from( + self.total_votes() + .checked_add(votes) + .ok_or(TipRouterError::ArithmeticOverflow)?, + ); + + if self.finalized() { + self.slot_finalized = PodU64::from(current_slot); + } + + Ok(()) + } } -#[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod)] +// PDA'd ["OPERATOR_SNAPSHOT", VAULT, OPERATOR, NCN, NCN_EPOCH_SLOT] +#[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] #[repr(C)] pub struct VaultOperatorDelegationSnapshot { vault: Pubkey, + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: PodU64, + bump: u8, + + slot_created: PodU64, + + is_active: PodBool, + st_mint: Pubkey, total_security: PodU64, total_votes: PodU128, - slot_set: PodU64, + reserved: [u8; 128], } -impl Default for VaultOperatorDelegationSnapshot { - fn default() -> Self { - Self { - vault: Pubkey::default(), - st_mint: Pubkey::default(), - total_security: PodU64::from(0), - total_votes: PodU128::from(0), - slot_set: PodU64::from(0), - reserved: [0; 128], - } - } +impl Discriminator for VaultOperatorDelegationSnapshot { + const DISCRIMINATOR: u8 = Discriminators::VaultOperatorDelegationSnapshot as u8; } impl VaultOperatorDelegationSnapshot { pub fn new( vault: Pubkey, + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: u64, + bump: u8, + current_slot: u64, + is_active: bool, st_mint: Pubkey, total_security: u64, total_votes: u128, - current_slot: u64, ) -> Self { Self { vault, + operator, + ncn, + ncn_epoch: PodU64::from(ncn_epoch), + bump, + slot_created: PodU64::from(current_slot), + is_active: PodBool::from(is_active), st_mint, total_security: PodU64::from(total_security), total_votes: PodU128::from(total_votes), - slot_set: PodU64::from(current_slot), reserved: [0; 128], } } - pub fn create_snapshot( + pub fn new_active( vault: Pubkey, - st_mint: Pubkey, - delegation_state: &DelegationState, - weight_table: &WeightTable, + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: u64, + bump: u8, current_slot: u64, - ) -> Result { - let total_security = delegation_state.total_security()?; - let precise_total_security = PreciseNumber::new(total_security as u128) - .ok_or(TipRouterError::NewPreciseNumberError)?; - - let precise_weight = weight_table.get_precise_weight(&st_mint)?; - - let precise_total_votes = precise_total_security - .checked_mul(&precise_weight) - .ok_or(TipRouterError::ArithmeticOverflow)?; - - let total_votes = precise_total_votes - .to_imprecise() - .ok_or(TipRouterError::CastToImpreciseNumberError)?; - - Ok(Self::new( + st_mint: Pubkey, + total_security: u64, + total_votes: u128, + ) -> Self { + Self::new( vault, + operator, + ncn, + ncn_epoch, + bump, + current_slot, + true, st_mint, total_security, total_votes, + ) + } + + pub fn new_inactive( + vault: Pubkey, + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: u64, + bump: u8, + current_slot: u64, + st_mint: Pubkey, + ) -> Self { + Self::new( + vault, + operator, + ncn, + ncn_epoch, + bump, current_slot, - )) + false, + st_mint, + 0, + 0, + ) } - pub fn is_empty(&self) -> bool { - self.slot_set.eq(&PodU64::from(0)) + pub fn seeds(vault: &Pubkey, operator: &Pubkey, ncn: &Pubkey, ncn_epoch: u64) -> Vec> { + Vec::from_iter( + [ + b"VAULT_OPERATOR_DELEGATION_SNAPSHOT".to_vec(), + vault.to_bytes().to_vec(), + operator.to_bytes().to_vec(), + ncn.to_bytes().to_vec(), + ncn_epoch.to_le_bytes().to_vec(), + ] + .iter() + .cloned(), + ) } - pub fn total_votes(&self) -> u128 { - self.total_votes.into() + pub fn find_program_address( + program_id: &Pubkey, + vault: &Pubkey, + operator: &Pubkey, + ncn: &Pubkey, + ncn_epoch: u64, + ) -> (Pubkey, u8, Vec>) { + let seeds = Self::seeds(vault, operator, ncn, ncn_epoch); + let seeds_iter: Vec<_> = seeds.iter().map(|s| s.as_slice()).collect(); + let (pda, bump) = Pubkey::find_program_address(&seeds_iter, program_id); + (pda, bump, seeds) + } + + pub fn load( + program_id: &Pubkey, + vault: &Pubkey, + operator: &Pubkey, + ncn: &Pubkey, + ncn_epoch: u64, + vault_operator_delegation_snapshot: &AccountInfo, + expect_writable: bool, + ) -> Result<(), ProgramError> { + if vault_operator_delegation_snapshot.owner.ne(program_id) { + msg!("Operator Snapshot account has an invalid owner"); + return Err(ProgramError::InvalidAccountOwner); + } + if vault_operator_delegation_snapshot.data_is_empty() { + msg!("Operator Snapshot account data is empty"); + return Err(ProgramError::InvalidAccountData); + } + if expect_writable && !vault_operator_delegation_snapshot.is_writable { + msg!("Operator Snapshot account is not writable"); + return Err(ProgramError::InvalidAccountData); + } + if vault_operator_delegation_snapshot.data.borrow()[0].ne(&Self::DISCRIMINATOR) { + msg!("Operator Snapshot account discriminator is invalid"); + return Err(ProgramError::InvalidAccountData); + } + if vault_operator_delegation_snapshot + .key + .ne(&Self::find_program_address(program_id, vault, operator, ncn, ncn_epoch).0) + { + msg!("Operator Snapshot account is not at the correct PDA"); + return Err(ProgramError::InvalidAccountData); + } + Ok(()) } } diff --git a/core/src/instruction.rs b/core/src/instruction.rs index 55210dd..df12d59 100644 --- a/core/src/instruction.rs +++ b/core/src/instruction.rs @@ -101,4 +101,24 @@ pub enum TipRouterInstruction { InitializeOperatorSnapshot{ first_slot_of_ncn_epoch: Option, }, + + /// Initializes the Vault Operator Delegation Snapshot + #[account(0, name = "ncn_config")] + #[account(1, name = "restaking_config")] + #[account(2, name = "ncn")] + #[account(3, name = "operator")] + #[account(4, name = "vault")] + #[account(5, name = "vault_ncn_ticket")] + #[account(6, name = "ncn_vault_ticket")] + #[account(7, name = "vault_operator_delegation")] + #[account(8, name = "weight_table")] + #[account(9, writable, name = "epoch_snapshot")] + #[account(10, writable, name = "operator_snapshot")] + #[account(11, writable, name = "vault_operator_delegation_snapshot")] + #[account(12, writable, signer, name = "payer")] + #[account(13, name = "restaking_program_id")] + #[account(14, name = "system_program")] + InitializeVaultOperatorDelegationSnapshot{ + first_slot_of_ncn_epoch: Option, + }, } diff --git a/program/src/initialize_operator_snapshot.rs b/program/src/initialize_operator_snapshot.rs index 398c9d4..dbc6726 100644 --- a/program/src/initialize_operator_snapshot.rs +++ b/program/src/initialize_operator_snapshot.rs @@ -56,19 +56,6 @@ pub fn process_initialize_operator_snapshot( EpochSnapshot::load(program_id, ncn.key, ncn_epoch, epoch_snapshot, true)?; - let is_active: bool = { - let ncn_operator_state_data = ncn_operator_state.data.borrow(); - let ncn_operator_state_account = - NcnOperatorState::try_from_slice_unchecked(&ncn_operator_state_data)?; - - ncn_operator_state_account - .ncn_opt_in_state - .is_active(current_slot, ncn_epoch_length) - && ncn_operator_state_account - .operator_opt_in_state - .is_active(current_slot, ncn_epoch_length) - }; - let (operator_snapshot_pubkey, operator_snapshot_bump, mut operator_snapshot_seeds) = EpochSnapshot::find_program_address(program_id, ncn.key, ncn_epoch); operator_snapshot_seeds.push(vec![operator_snapshot_bump]); @@ -96,22 +83,38 @@ pub fn process_initialize_operator_snapshot( &operator_snapshot_seeds, )?; - let (operator_fee_bps, vault_count): (u16, u64) = { - let operator_data = operator.data.borrow(); - let operator_account = Operator::try_from_slice_unchecked(&operator_data)?; - ( - operator_account.operator_fee_bps.into(), - operator_account.vault_count(), - ) + let is_active: bool = { + let ncn_operator_state_data = ncn_operator_state.data.borrow(); + let ncn_operator_state_account = + NcnOperatorState::try_from_slice_unchecked(&ncn_operator_state_data)?; + + let ncn_operator_okay = ncn_operator_state_account + .ncn_opt_in_state + .is_active(current_slot, ncn_epoch_length); + + let operator_ncn_okay = ncn_operator_state_account + .operator_opt_in_state + .is_active(current_slot, ncn_epoch_length); + + ncn_operator_okay && operator_ncn_okay }; let mut operator_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = operator_snapshot.try_borrow_mut_data()?; - operator_snapshot_data[0] = EpochSnapshot::DISCRIMINATOR; + operator_snapshot_data[0] = OperatorSnapshot::DISCRIMINATOR; let operator_snapshot_account = OperatorSnapshot::try_from_slice_unchecked_mut(&mut operator_snapshot_data)?; *operator_snapshot_account = if is_active { + let (operator_fee_bps, vault_count): (u16, u64) = { + let operator_data = operator.data.borrow(); + let operator_account = Operator::try_from_slice_unchecked(&operator_data)?; + ( + operator_account.operator_fee_bps.into(), + operator_account.vault_count(), + ) + }; + OperatorSnapshot::new_active( *operator.key, *ncn.key, diff --git a/program/src/initialize_vault_operator_delegation_snapshot.rs b/program/src/initialize_vault_operator_delegation_snapshot.rs new file mode 100644 index 0000000..fd40193 --- /dev/null +++ b/program/src/initialize_vault_operator_delegation_snapshot.rs @@ -0,0 +1,200 @@ +use jito_bytemuck::{AccountDeserialize, Discriminator}; +use jito_jsm_core::{ + create_account, + loader::{load_signer, load_system_account, load_system_program}, +}; +use jito_restaking_core::{ + config::Config, ncn::Ncn, ncn_vault_ticket::NcnVaultTicket, operator::Operator, +}; +use jito_tip_router_core::{ + epoch_snapshot::{EpochSnapshot, OperatorSnapshot, VaultOperatorDelegationSnapshot}, + loaders::load_ncn_epoch, + ncn_config::NcnConfig, + weight_table::WeightTable, +}; +use jito_vault_core::{ + vault::Vault, vault_ncn_ticket::VaultNcnTicket, + vault_operator_delegation::VaultOperatorDelegation, +}; +use solana_program::{ + account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, + program_error::ProgramError, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, +}; + +pub fn process_initialize_vault_operator_delegation_snapshot( + program_id: &Pubkey, + accounts: &[AccountInfo], + first_slot_of_ncn_epoch: Option, +) -> ProgramResult { + let [ncn_config, restaking_config, ncn, operator, vault, vault_ncn_ticket, ncn_vault_ticket, vault_operator_delegation, weight_table, epoch_snapshot, operator_snapshot, vault_operator_delegation_snapshot, payer, restaking_program_id, system_program] = + accounts + else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if restaking_program_id.key.ne(&jito_restaking_program::id()) { + msg!("Incorrect restaking program ID"); + return Err(ProgramError::InvalidAccountData); + } + + NcnConfig::load(program_id, ncn.key, ncn_config, false)?; + Config::load(restaking_program_id.key, restaking_config, false)?; + Ncn::load(restaking_program_id.key, ncn, false)?; + Operator::load(restaking_program_id.key, operator, false)?; + Vault::load(restaking_program_id.key, vault, false)?; + + VaultNcnTicket::load( + restaking_program_id.key, + vault_ncn_ticket, + vault, + ncn, + false, + )?; + NcnVaultTicket::load( + restaking_program_id.key, + ncn_vault_ticket, + ncn, + vault, + false, + )?; + + //TODO check that st mint is supported? + //TODO may not exist + if !vault_operator_delegation.data_is_empty() { + VaultOperatorDelegation::load( + restaking_program_id.key, + vault_operator_delegation, + vault, + operator, + false, + )?; + } + + load_system_account(vault_operator_delegation_snapshot, true)?; + load_system_program(system_program)?; + //TODO check that it is not writable + load_signer(payer, false)?; + + let current_slot = Clock::get()?.slot; + let (ncn_epoch, ncn_epoch_length) = + load_ncn_epoch(restaking_config, current_slot, first_slot_of_ncn_epoch)?; + + WeightTable::load(program_id, weight_table, ncn, ncn_epoch, false)?; + EpochSnapshot::load(program_id, ncn.key, ncn_epoch, epoch_snapshot, true)?; + OperatorSnapshot::load( + program_id, + operator.key, + ncn.key, + ncn_epoch, + epoch_snapshot, + true, + )?; + + let ( + vault_operator_delegation_snapshot_pubkey, + vault_operator_delegation_snapshot_bump, + mut vault_operator_delegation_snapshot_seeds, + ) = VaultOperatorDelegationSnapshot::find_program_address( + program_id, + vault.key, + operator.key, + ncn.key, + ncn_epoch, + ); + vault_operator_delegation_snapshot_seeds.push(vec![vault_operator_delegation_snapshot_bump]); + + if vault_operator_delegation_snapshot_pubkey.ne(operator_snapshot.key) { + msg!("Incorrect vault operator delegation snapshot PDA"); + return Err(ProgramError::InvalidAccountData); + } + + msg!( + "Initializing vault operator delegation snapshot {} for NCN: {} at epoch: {}", + epoch_snapshot.key, + ncn.key, + ncn_epoch + ); + create_account( + payer, + operator_snapshot, + system_program, + program_id, + &Rent::get()?, + 8_u64 + .checked_add(std::mem::size_of::() as u64) + .unwrap(), + &vault_operator_delegation_snapshot_seeds, + )?; + + let is_active: bool = { + let vault_ncn_ticket_data = vault_ncn_ticket.data.borrow(); + let vault_ncn_ticket_account = + VaultNcnTicket::try_from_slice_unchecked(&vault_ncn_ticket_data)?; + + let ncn_vault_ticket_data = ncn_vault_ticket.data.borrow(); + let ncn_vault_ticket_account = + NcnVaultTicket::try_from_slice_unchecked(&ncn_vault_ticket_data)?; + + let vault_ncn_okay = vault_ncn_ticket_account + .state + .is_active(current_slot, ncn_epoch_length); + + let ncn_vault_okay = ncn_vault_ticket_account + .state + .is_active(current_slot, ncn_epoch_length); + + let delegation_dne = vault_operator_delegation.data_is_empty(); + + vault_ncn_okay && ncn_vault_okay && delegation_dne + }; + + let mut vault_operator_delegation_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = + operator_snapshot.try_borrow_mut_data()?; + vault_operator_delegation_snapshot_data[0] = VaultOperatorDelegationSnapshot::DISCRIMINATOR; + let vault_operator_delegation_snapshot_account = + VaultOperatorDelegationSnapshot::try_from_slice_unchecked_mut( + &mut vault_operator_delegation_snapshot_data, + )?; + + *vault_operator_delegation_snapshot_account = if is_active { + let (operator_fee_bps, vault_count): (u16, u64) = { + let operator_data = operator.data.borrow(); + let operator_account = Operator::try_from_slice_unchecked(&operator_data)?; + ( + operator_account.operator_fee_bps.into(), + operator_account.vault_count(), + ) + }; + + //TODO Ending here for the day + VaultOperatorDelegationSnapshot::new_active( + *vault.key, + *operator.key, + *ncn.key, + ncn_epoch, + vault_operator_delegation_snapshot_bump, + current_slot, + operator_fee_bps, + vault_count, + ) + } else { + VaultOperatorDelegationSnapshot::new_inactive( + *operator.key, + *ncn.key, + ncn_epoch, + vault_operator_delegation_snapshot_bump, + current_slot, + ) + }; + + // Increment operator registration for an inactive operator + if !is_active { + let mut epoch_snapshot_data = epoch_snapshot.try_borrow_mut_data()?; + let epoch_snapshot_account = + EpochSnapshot::try_from_slice_unchecked_mut(&mut epoch_snapshot_data)?; + + epoch_snapshot_account.increment_operator_registration(current_slot, 0, 0)?; + } + + Ok(()) +} diff --git a/program/src/lib.rs b/program/src/lib.rs index 6b2e4c6..08658d3 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -2,6 +2,7 @@ mod admin_update_weight_table; mod initialize_epoch_snapshot; mod initialize_ncn_config; mod initialize_operator_snapshot; +mod initialize_vault_operator_delegation_snapshot; mod initialize_weight_table; mod set_config_fees; mod set_new_admin; @@ -22,6 +23,7 @@ use crate::{ initialize_epoch_snapshot::process_initialize_epoch_snapshot, initialize_ncn_config::process_initialize_ncn_config, initialize_operator_snapshot::process_initialize_operator_snapshot, + initialize_vault_operator_delegation_snapshot::process_initialize_vault_operator_delegation_snapshot, initialize_weight_table::process_initialize_weight_table, set_config_fees::process_set_config_fees, }; @@ -90,6 +92,16 @@ pub fn process_instruction( msg!("Instruction: InitializeOperatorSnapshot"); process_initialize_operator_snapshot(program_id, accounts, first_slot_of_ncn_epoch) } + TipRouterInstruction::InitializeVaultOperatorDelegationSnapshot { + first_slot_of_ncn_epoch, + } => { + msg!("Instruction: InitializeVaultOperatorDelegationSnapshot"); + process_initialize_vault_operator_delegation_snapshot( + program_id, + accounts, + first_slot_of_ncn_epoch, + ) + } // ------------------------------------------ // Update // ------------------------------------------ From bd7e3b1a62dc65db0a046fa6aae7b8be3f99bee2 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Tue, 12 Nov 2024 08:25:26 -0800 Subject: [PATCH 06/28] working --- core/src/epoch_snapshot.rs | 62 ++++++++++++++++++- core/src/error.rs | 4 ++ ...lize_vault_operator_delegation_snapshot.rs | 52 +++++++++++----- 3 files changed, 102 insertions(+), 16 deletions(-) diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index 251ad99..5a7122e 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -3,10 +3,14 @@ use jito_bytemuck::{ types::{PodBool, PodU128, PodU16, PodU64}, AccountDeserialize, Discriminator, }; +use jito_vault_core::vault_operator_delegation::VaultOperatorDelegation; use shank::{ShankAccount, ShankType}; use solana_program::{account_info::AccountInfo, msg, program_error::ProgramError, pubkey::Pubkey}; +use spl_math::precise_number::PreciseNumber; -use crate::{discriminators::Discriminators, error::TipRouterError, fees::Fees}; +use crate::{ + discriminators::Discriminators, error::TipRouterError, fees::Fees, weight_table::WeightTable, +}; // PDA'd ["EPOCH_SNAPSHOT", NCN, NCN_EPOCH_SLOT] #[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] @@ -150,6 +154,10 @@ impl EpochSnapshot { vault_operator_delegations: u64, votes: u128, ) -> Result<(), TipRouterError> { + if self.finalized() { + return Err(TipRouterError::OperatorFinalized.into()); + } + self.operators_registered = PodU64::from( self.operators_registered() .checked_add(1) @@ -352,6 +360,10 @@ impl OperatorSnapshot { vault_operator_delegations: u64, votes: u128, ) -> Result<(), TipRouterError> { + if self.finalized() { + return Err(TipRouterError::VaultOperatorDelegationFinalized.into()); + } + self.vault_operator_delegations_registered = PodU64::from( self.vault_operator_delegations_registered() .checked_add(1) @@ -479,6 +491,46 @@ impl VaultOperatorDelegationSnapshot { ) } + pub fn create_snapshot( + vault: Pubkey, + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: u64, + bump: u8, + current_slot: u64, + st_mint: Pubkey, + vault_operator_delegation: &VaultOperatorDelegation, + weight_table: &WeightTable, + ) -> Result { + let total_security = vault_operator_delegation + .delegation_state + .total_security()?; + let precise_total_security = PreciseNumber::new(total_security as u128) + .ok_or(TipRouterError::NewPreciseNumberError)?; + + let precise_weight = weight_table.get_precise_weight(&st_mint)?; + + let precise_total_votes = precise_total_security + .checked_mul(&precise_weight) + .ok_or(TipRouterError::ArithmeticOverflow)?; + + let total_votes = precise_total_votes + .to_imprecise() + .ok_or(TipRouterError::CastToImpreciseNumberError)?; + + Ok(Self::new_active( + vault, + operator, + ncn, + ncn_epoch, + bump, + current_slot, + st_mint, + total_security, + total_votes, + )) + } + pub fn seeds(vault: &Pubkey, operator: &Pubkey, ncn: &Pubkey, ncn_epoch: u64) -> Vec> { Vec::from_iter( [ @@ -540,4 +592,12 @@ impl VaultOperatorDelegationSnapshot { } Ok(()) } + + pub fn total_security(&self) -> u64 { + self.total_security.into() + } + + pub fn total_votes(&self) -> u128 { + self.total_votes.into() + } } diff --git a/core/src/error.rs b/core/src/error.rs index 4d6cca0..458e7e9 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -46,6 +46,10 @@ pub enum TipRouterError { WeightNotFound, #[error("No operators in ncn")] NoOperators, + #[error("Vault operator delegation is already finalized - should not happen")] + VaultOperatorDelegationFinalized, + #[error("Operator is already finalized - should not happen")] + OperatorFinalized, } impl DecodeError for TipRouterError { diff --git a/program/src/initialize_vault_operator_delegation_snapshot.rs b/program/src/initialize_vault_operator_delegation_snapshot.rs index fd40193..12b9f4a 100644 --- a/program/src/initialize_vault_operator_delegation_snapshot.rs +++ b/program/src/initialize_vault_operator_delegation_snapshot.rs @@ -126,6 +126,12 @@ pub fn process_initialize_vault_operator_delegation_snapshot( &vault_operator_delegation_snapshot_seeds, )?; + let st_mint = { + let vault_data = vault.data.borrow(); + let vault_account = Vault::try_from_slice_unchecked(&vault_data)?; + vault_account.supported_mint + }; + let is_active: bool = { let vault_ncn_ticket_data = vault_ncn_ticket.data.borrow(); let vault_ncn_ticket_account = @@ -157,43 +163,59 @@ pub fn process_initialize_vault_operator_delegation_snapshot( )?; *vault_operator_delegation_snapshot_account = if is_active { - let (operator_fee_bps, vault_count): (u16, u64) = { - let operator_data = operator.data.borrow(); - let operator_account = Operator::try_from_slice_unchecked(&operator_data)?; - ( - operator_account.operator_fee_bps.into(), - operator_account.vault_count(), - ) - }; + let vault_operator_delegation_data = vault_operator_delegation.data.borrow(); + let vault_operator_delegation_account = + VaultOperatorDelegation::try_from_slice_unchecked(&vault_operator_delegation_data)?; + + let weight_table_data = weight_table.data.borrow(); + let weight_table_account = WeightTable::try_from_slice_unchecked(&weight_table_data)?; //TODO Ending here for the day - VaultOperatorDelegationSnapshot::new_active( + VaultOperatorDelegationSnapshot::create_snapshot( *vault.key, *operator.key, *ncn.key, ncn_epoch, vault_operator_delegation_snapshot_bump, current_slot, - operator_fee_bps, - vault_count, - ) + st_mint, + vault_operator_delegation_account, + weight_table_account, + )? } else { VaultOperatorDelegationSnapshot::new_inactive( + *vault.key, *operator.key, *ncn.key, ncn_epoch, vault_operator_delegation_snapshot_bump, current_slot, + st_mint, ) }; - // Increment operator registration for an inactive operator - if !is_active { + // Increment vault operator delegation + let mut operator_snapshot_data = operator_snapshot.try_borrow_mut_data()?; + let operator_snapshot_account = + OperatorSnapshot::try_from_slice_unchecked_mut(&mut operator_snapshot_data)?; + + operator_snapshot_account.increment_vault_operator_delegation_registration( + current_slot, + vault_operator_delegation_snapshot_account.total_security(), + vault_operator_delegation_snapshot_account.total_votes(), + )?; + + // If operator is finalized, increment operator registration + if operator_snapshot_account.finalized() { let mut epoch_snapshot_data = epoch_snapshot.try_borrow_mut_data()?; let epoch_snapshot_account = EpochSnapshot::try_from_slice_unchecked_mut(&mut epoch_snapshot_data)?; - epoch_snapshot_account.increment_operator_registration(current_slot, 0, 0)?; + epoch_snapshot_account.increment_operator_registration( + current_slot, + operator_snapshot_account.valid_operator_vault_delegations(), + operator_snapshot_account.total_votes(), + )?; } Ok(()) From b5d77e02478bdef8a825de6288754a6291201cb5 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Tue, 12 Nov 2024 09:00:53 -0800 Subject: [PATCH 07/28] updated clients --- .../jito_tip_router/accounts/epochSnapshot.ts | 16 +- clients/js/jito_tip_router/accounts/index.ts | 1 + .../accounts/operatorSnapshot.ts | 62 +- .../vaultOperatorDelegationSnapshot.ts | 189 ++++ .../jito_tip_router/errors/jitoTipRouter.ts | 12 + .../js/jito_tip_router/instructions/index.ts | 2 + .../initializeOperatorSnapshot.ts | 334 +++++++ ...itializeVaultOperatorDelegationSnapshot.ts | 417 ++++++++ .../jito_tip_router/programs/jitoTipRouter.ts | 19 +- clients/js/jito_tip_router/types/index.ts | 1 - .../types/vaultOperatorDelegationSnapshot.ts | 77 -- .../src/generated/accounts/epoch_snapshot.rs | 4 +- .../src/generated/accounts/mod.rs | 6 +- .../generated/accounts/operator_snapshot.rs | 13 +- .../vault_operator_delegation_snapshot.rs | 88 ++ .../src/generated/errors/jito_tip_router.rs | 9 + .../initialize_operator_snapshot.rs | 692 ++++++++++++++ ...lize_vault_operator_delegation_snapshot.rs | 899 ++++++++++++++++++ .../src/generated/instructions/mod.rs | 3 + .../src/generated/types/mod.rs | 6 +- .../vault_operator_delegation_snapshot.rs | 28 - core/src/epoch_snapshot.rs | 9 +- idl/jito_tip_router.json | 329 +++++-- scripts/generate-clients.js | 16 + 24 files changed, 3009 insertions(+), 223 deletions(-) create mode 100644 clients/js/jito_tip_router/accounts/vaultOperatorDelegationSnapshot.ts create mode 100644 clients/js/jito_tip_router/instructions/initializeOperatorSnapshot.ts create mode 100644 clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts delete mode 100644 clients/js/jito_tip_router/types/vaultOperatorDelegationSnapshot.ts create mode 100644 clients/rust/jito_tip_router/src/generated/accounts/vault_operator_delegation_snapshot.rs create mode 100644 clients/rust/jito_tip_router/src/generated/instructions/initialize_operator_snapshot.rs create mode 100644 clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs delete mode 100644 clients/rust/jito_tip_router/src/generated/types/vault_operator_delegation_snapshot.rs diff --git a/clients/js/jito_tip_router/accounts/epochSnapshot.ts b/clients/js/jito_tip_router/accounts/epochSnapshot.ts index 3c6a279..86bfa4c 100644 --- a/clients/js/jito_tip_router/accounts/epochSnapshot.ts +++ b/clients/js/jito_tip_router/accounts/epochSnapshot.ts @@ -47,11 +47,13 @@ export type EpochSnapshot = { discriminator: bigint; ncn: Address; ncnEpoch: bigint; - slotCreated: bigint; bump: number; + slotCreated: bigint; + slotFinalized: bigint; ncnFees: Fees; operatorCount: bigint; operatorsRegistered: bigint; + validOperatorVaultDelegations: bigint; totalVotes: bigint; reserved: Array; }; @@ -60,11 +62,13 @@ export type EpochSnapshotArgs = { discriminator: number | bigint; ncn: Address; ncnEpoch: number | bigint; - slotCreated: number | bigint; bump: number; + slotCreated: number | bigint; + slotFinalized: number | bigint; ncnFees: FeesArgs; operatorCount: number | bigint; operatorsRegistered: number | bigint; + validOperatorVaultDelegations: number | bigint; totalVotes: number | bigint; reserved: Array; }; @@ -74,11 +78,13 @@ export function getEpochSnapshotEncoder(): Encoder { ['discriminator', getU64Encoder()], ['ncn', getAddressEncoder()], ['ncnEpoch', getU64Encoder()], - ['slotCreated', getU64Encoder()], ['bump', getU8Encoder()], + ['slotCreated', getU64Encoder()], + ['slotFinalized', getU64Encoder()], ['ncnFees', getFeesEncoder()], ['operatorCount', getU64Encoder()], ['operatorsRegistered', getU64Encoder()], + ['validOperatorVaultDelegations', getU64Encoder()], ['totalVotes', getU128Encoder()], ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], ]); @@ -89,11 +95,13 @@ export function getEpochSnapshotDecoder(): Decoder { ['discriminator', getU64Decoder()], ['ncn', getAddressDecoder()], ['ncnEpoch', getU64Decoder()], - ['slotCreated', getU64Decoder()], ['bump', getU8Decoder()], + ['slotCreated', getU64Decoder()], + ['slotFinalized', getU64Decoder()], ['ncnFees', getFeesDecoder()], ['operatorCount', getU64Decoder()], ['operatorsRegistered', getU64Decoder()], + ['validOperatorVaultDelegations', getU64Decoder()], ['totalVotes', getU128Decoder()], ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], ]); diff --git a/clients/js/jito_tip_router/accounts/index.ts b/clients/js/jito_tip_router/accounts/index.ts index 6fa7098..9aba2f1 100644 --- a/clients/js/jito_tip_router/accounts/index.ts +++ b/clients/js/jito_tip_router/accounts/index.ts @@ -9,4 +9,5 @@ export * from './epochSnapshot'; export * from './ncnConfig'; export * from './operatorSnapshot'; +export * from './vaultOperatorDelegationSnapshot'; export * from './weightTable'; diff --git a/clients/js/jito_tip_router/accounts/operatorSnapshot.ts b/clients/js/jito_tip_router/accounts/operatorSnapshot.ts index ae46a96..ff9dddf 100644 --- a/clients/js/jito_tip_router/accounts/operatorSnapshot.ts +++ b/clients/js/jito_tip_router/accounts/operatorSnapshot.ts @@ -17,6 +17,8 @@ import { getAddressEncoder, getArrayDecoder, getArrayEncoder, + getBoolDecoder, + getBoolEncoder, getStructDecoder, getStructEncoder, getU128Decoder, @@ -38,26 +40,21 @@ import { type MaybeAccount, type MaybeEncodedAccount, } from '@solana/web3.js'; -import { - getVaultOperatorDelegationSnapshotDecoder, - getVaultOperatorDelegationSnapshotEncoder, - type VaultOperatorDelegationSnapshot, - type VaultOperatorDelegationSnapshotArgs, -} from '../types'; export type OperatorSnapshot = { discriminator: bigint; operator: Address; ncn: Address; ncnEpoch: bigint; - slotCreated: bigint; bump: number; + slotCreated: bigint; + slotFinalized: bigint; + isActive: number; operatorFeeBps: number; + vaultOperatorDelegationCount: bigint; + vaultOperatorDelegationsRegistered: bigint; + validOperatorVaultDelegations: bigint; totalVotes: bigint; - numVaultOperatorDelegations: number; - vaultOperatorDelegationsRegistered: number; - slotSet: bigint; - vaultOperatorDelegations: Array; reserved: Array; }; @@ -66,14 +63,15 @@ export type OperatorSnapshotArgs = { operator: Address; ncn: Address; ncnEpoch: number | bigint; - slotCreated: number | bigint; bump: number; + slotCreated: number | bigint; + slotFinalized: number | bigint; + isActive: number; operatorFeeBps: number; + vaultOperatorDelegationCount: number | bigint; + vaultOperatorDelegationsRegistered: number | bigint; + validOperatorVaultDelegations: number | bigint; totalVotes: number | bigint; - numVaultOperatorDelegations: number; - vaultOperatorDelegationsRegistered: number; - slotSet: number | bigint; - vaultOperatorDelegations: Array; reserved: Array; }; @@ -83,19 +81,15 @@ export function getOperatorSnapshotEncoder(): Encoder { ['operator', getAddressEncoder()], ['ncn', getAddressEncoder()], ['ncnEpoch', getU64Encoder()], - ['slotCreated', getU64Encoder()], ['bump', getU8Encoder()], + ['slotCreated', getU64Encoder()], + ['slotFinalized', getU64Encoder()], + ['isActive', getBoolEncoder()], ['operatorFeeBps', getU16Encoder()], + ['vaultOperatorDelegationCount', getU64Encoder()], + ['vaultOperatorDelegationsRegistered', getU64Encoder()], + ['validOperatorVaultDelegations', getU64Encoder()], ['totalVotes', getU128Encoder()], - ['numVaultOperatorDelegations', getU16Encoder()], - ['vaultOperatorDelegationsRegistered', getU16Encoder()], - ['slotSet', getU64Encoder()], - [ - 'vaultOperatorDelegations', - getArrayEncoder(getVaultOperatorDelegationSnapshotEncoder(), { - size: 32, - }), - ], ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], ]); } @@ -106,19 +100,15 @@ export function getOperatorSnapshotDecoder(): Decoder { ['operator', getAddressDecoder()], ['ncn', getAddressDecoder()], ['ncnEpoch', getU64Decoder()], - ['slotCreated', getU64Decoder()], ['bump', getU8Decoder()], + ['slotCreated', getU64Decoder()], + ['slotFinalized', getU64Decoder()], + ['isActive', getBoolDecoder()], ['operatorFeeBps', getU16Decoder()], + ['vaultOperatorDelegationCount', getU64Decoder()], + ['vaultOperatorDelegationsRegistered', getU64Decoder()], + ['validOperatorVaultDelegations', getU64Decoder()], ['totalVotes', getU128Decoder()], - ['numVaultOperatorDelegations', getU16Decoder()], - ['vaultOperatorDelegationsRegistered', getU16Decoder()], - ['slotSet', getU64Decoder()], - [ - 'vaultOperatorDelegations', - getArrayDecoder(getVaultOperatorDelegationSnapshotDecoder(), { - size: 32, - }), - ], ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], ]); } diff --git a/clients/js/jito_tip_router/accounts/vaultOperatorDelegationSnapshot.ts b/clients/js/jito_tip_router/accounts/vaultOperatorDelegationSnapshot.ts new file mode 100644 index 0000000..c0233f5 --- /dev/null +++ b/clients/js/jito_tip_router/accounts/vaultOperatorDelegationSnapshot.ts @@ -0,0 +1,189 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/kinobi-so/kinobi + */ + +import { + assertAccountExists, + assertAccountsExist, + combineCodec, + decodeAccount, + fetchEncodedAccount, + fetchEncodedAccounts, + getAddressDecoder, + getAddressEncoder, + getArrayDecoder, + getArrayEncoder, + getBoolDecoder, + getBoolEncoder, + getStructDecoder, + getStructEncoder, + getU128Decoder, + getU128Encoder, + getU64Decoder, + getU64Encoder, + getU8Decoder, + getU8Encoder, + type Account, + type Address, + type Codec, + type Decoder, + type EncodedAccount, + type Encoder, + type FetchAccountConfig, + type FetchAccountsConfig, + type MaybeAccount, + type MaybeEncodedAccount, +} from '@solana/web3.js'; + +export type VaultOperatorDelegationSnapshot = { + discriminator: bigint; + vault: Address; + operator: Address; + ncn: Address; + ncnEpoch: bigint; + bump: number; + slotCreated: bigint; + isActive: number; + stMint: Address; + totalSecurity: bigint; + totalVotes: bigint; + reserved: Array; +}; + +export type VaultOperatorDelegationSnapshotArgs = { + discriminator: number | bigint; + vault: Address; + operator: Address; + ncn: Address; + ncnEpoch: number | bigint; + bump: number; + slotCreated: number | bigint; + isActive: number; + stMint: Address; + totalSecurity: number | bigint; + totalVotes: number | bigint; + reserved: Array; +}; + +export function getVaultOperatorDelegationSnapshotEncoder(): Encoder { + return getStructEncoder([ + ['discriminator', getU64Encoder()], + ['vault', getAddressEncoder()], + ['operator', getAddressEncoder()], + ['ncn', getAddressEncoder()], + ['ncnEpoch', getU64Encoder()], + ['bump', getU8Encoder()], + ['slotCreated', getU64Encoder()], + ['isActive', getBoolEncoder()], + ['stMint', getAddressEncoder()], + ['totalSecurity', getU64Encoder()], + ['totalVotes', getU128Encoder()], + ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], + ]); +} + +export function getVaultOperatorDelegationSnapshotDecoder(): Decoder { + return getStructDecoder([ + ['discriminator', getU64Decoder()], + ['vault', getAddressDecoder()], + ['operator', getAddressDecoder()], + ['ncn', getAddressDecoder()], + ['ncnEpoch', getU64Decoder()], + ['bump', getU8Decoder()], + ['slotCreated', getU64Decoder()], + ['isActive', getBoolDecoder()], + ['stMint', getAddressDecoder()], + ['totalSecurity', getU64Decoder()], + ['totalVotes', getU128Decoder()], + ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], + ]); +} + +export function getVaultOperatorDelegationSnapshotCodec(): Codec< + VaultOperatorDelegationSnapshotArgs, + VaultOperatorDelegationSnapshot +> { + return combineCodec( + getVaultOperatorDelegationSnapshotEncoder(), + getVaultOperatorDelegationSnapshotDecoder() + ); +} + +export function decodeVaultOperatorDelegationSnapshot< + TAddress extends string = string, +>( + encodedAccount: EncodedAccount +): Account; +export function decodeVaultOperatorDelegationSnapshot< + TAddress extends string = string, +>( + encodedAccount: MaybeEncodedAccount +): MaybeAccount; +export function decodeVaultOperatorDelegationSnapshot< + TAddress extends string = string, +>( + encodedAccount: EncodedAccount | MaybeEncodedAccount +): + | Account + | MaybeAccount { + return decodeAccount( + encodedAccount as MaybeEncodedAccount, + getVaultOperatorDelegationSnapshotDecoder() + ); +} + +export async function fetchVaultOperatorDelegationSnapshot< + TAddress extends string = string, +>( + rpc: Parameters[0], + address: Address, + config?: FetchAccountConfig +): Promise> { + const maybeAccount = await fetchMaybeVaultOperatorDelegationSnapshot( + rpc, + address, + config + ); + assertAccountExists(maybeAccount); + return maybeAccount; +} + +export async function fetchMaybeVaultOperatorDelegationSnapshot< + TAddress extends string = string, +>( + rpc: Parameters[0], + address: Address, + config?: FetchAccountConfig +): Promise> { + const maybeAccount = await fetchEncodedAccount(rpc, address, config); + return decodeVaultOperatorDelegationSnapshot(maybeAccount); +} + +export async function fetchAllVaultOperatorDelegationSnapshot( + rpc: Parameters[0], + addresses: Array
, + config?: FetchAccountsConfig +): Promise[]> { + const maybeAccounts = await fetchAllMaybeVaultOperatorDelegationSnapshot( + rpc, + addresses, + config + ); + assertAccountsExist(maybeAccounts); + return maybeAccounts; +} + +export async function fetchAllMaybeVaultOperatorDelegationSnapshot( + rpc: Parameters[0], + addresses: Array
, + config?: FetchAccountsConfig +): Promise[]> { + const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config); + return maybeAccounts.map((maybeAccount) => + decodeVaultOperatorDelegationSnapshot(maybeAccount) + ); +} diff --git a/clients/js/jito_tip_router/errors/jitoTipRouter.ts b/clients/js/jito_tip_router/errors/jitoTipRouter.ts index 62f7679..11a6a32 100644 --- a/clients/js/jito_tip_router/errors/jitoTipRouter.ts +++ b/clients/js/jito_tip_router/errors/jitoTipRouter.ts @@ -54,6 +54,12 @@ export const JITO_TIP_ROUTER_ERROR__INCORRECT_FEE_ADMIN = 0x220c; // 8716 export const JITO_TIP_ROUTER_ERROR__WEIGHT_TABLE_NOT_FINALIZED = 0x220d; // 8717 /** WeightNotFound: Weight not found */ export const JITO_TIP_ROUTER_ERROR__WEIGHT_NOT_FOUND = 0x220e; // 8718 +/** NoOperators: No operators in ncn */ +export const JITO_TIP_ROUTER_ERROR__NO_OPERATORS = 0x220f; // 8719 +/** VaultOperatorDelegationFinalized: Vault operator delegation is already finalized - should not happen */ +export const JITO_TIP_ROUTER_ERROR__VAULT_OPERATOR_DELEGATION_FINALIZED = 0x2210; // 8720 +/** OperatorFinalized: Operator is already finalized - should not happen */ +export const JITO_TIP_ROUTER_ERROR__OPERATOR_FINALIZED = 0x2211; // 8721 export type JitoTipRouterError = | typeof JITO_TIP_ROUTER_ERROR__ARITHMETIC_OVERFLOW @@ -70,7 +76,10 @@ export type JitoTipRouterError = | typeof JITO_TIP_ROUTER_ERROR__MODULO_OVERFLOW | typeof JITO_TIP_ROUTER_ERROR__NEW_PRECISE_NUMBER_ERROR | typeof JITO_TIP_ROUTER_ERROR__NO_MINTS_IN_TABLE + | typeof JITO_TIP_ROUTER_ERROR__NO_OPERATORS + | typeof JITO_TIP_ROUTER_ERROR__OPERATOR_FINALIZED | typeof JITO_TIP_ROUTER_ERROR__TOO_MANY_MINTS_FOR_TABLE + | typeof JITO_TIP_ROUTER_ERROR__VAULT_OPERATOR_DELEGATION_FINALIZED | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_LENGTH | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_MINT_HASH | typeof JITO_TIP_ROUTER_ERROR__WEIGHT_NOT_FOUND @@ -94,7 +103,10 @@ if (process.env.NODE_ENV !== 'production') { [JITO_TIP_ROUTER_ERROR__MODULO_OVERFLOW]: `Modulo Overflow`, [JITO_TIP_ROUTER_ERROR__NEW_PRECISE_NUMBER_ERROR]: `New precise number error`, [JITO_TIP_ROUTER_ERROR__NO_MINTS_IN_TABLE]: `There are no mints in the table`, + [JITO_TIP_ROUTER_ERROR__NO_OPERATORS]: `No operators in ncn`, + [JITO_TIP_ROUTER_ERROR__OPERATOR_FINALIZED]: `Operator is already finalized - should not happen`, [JITO_TIP_ROUTER_ERROR__TOO_MANY_MINTS_FOR_TABLE]: `Too many mints for table`, + [JITO_TIP_ROUTER_ERROR__VAULT_OPERATOR_DELEGATION_FINALIZED]: `Vault operator delegation is already finalized - should not happen`, [JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_LENGTH]: `Weight mints do not match - length`, [JITO_TIP_ROUTER_ERROR__WEIGHT_MINTS_DO_NOT_MATCH_MINT_HASH]: `Weight mints do not match - mint hash`, [JITO_TIP_ROUTER_ERROR__WEIGHT_NOT_FOUND]: `Weight not found`, diff --git a/clients/js/jito_tip_router/instructions/index.ts b/clients/js/jito_tip_router/instructions/index.ts index 18c4550..3ea3457 100644 --- a/clients/js/jito_tip_router/instructions/index.ts +++ b/clients/js/jito_tip_router/instructions/index.ts @@ -9,6 +9,8 @@ export * from './adminUpdateWeightTable'; export * from './initializeEpochSnapshot'; export * from './initializeNCNConfig'; +export * from './initializeOperatorSnapshot'; +export * from './initializeVaultOperatorDelegationSnapshot'; export * from './initializeWeightTable'; export * from './setConfigFees'; export * from './setNewAdmin'; diff --git a/clients/js/jito_tip_router/instructions/initializeOperatorSnapshot.ts b/clients/js/jito_tip_router/instructions/initializeOperatorSnapshot.ts new file mode 100644 index 0000000..aa74bff --- /dev/null +++ b/clients/js/jito_tip_router/instructions/initializeOperatorSnapshot.ts @@ -0,0 +1,334 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/kinobi-so/kinobi + */ + +import { + combineCodec, + getOptionDecoder, + getOptionEncoder, + getStructDecoder, + getStructEncoder, + getU64Decoder, + getU64Encoder, + getU8Decoder, + getU8Encoder, + transformEncoder, + type Address, + type Codec, + type Decoder, + type Encoder, + type IAccountMeta, + type IAccountSignerMeta, + type IInstruction, + type IInstructionWithAccounts, + type IInstructionWithData, + type Option, + type OptionOrNullable, + type ReadonlyAccount, + type TransactionSigner, + type WritableAccount, + type WritableSignerAccount, +} from '@solana/web3.js'; +import { JITO_TIP_ROUTER_PROGRAM_ADDRESS } from '../programs'; +import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; + +export const INITIALIZE_OPERATOR_SNAPSHOT_DISCRIMINATOR = 6; + +export function getInitializeOperatorSnapshotDiscriminatorBytes() { + return getU8Encoder().encode(INITIALIZE_OPERATOR_SNAPSHOT_DISCRIMINATOR); +} + +export type InitializeOperatorSnapshotInstruction< + TProgram extends string = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, + TAccountNcnConfig extends string | IAccountMeta = string, + TAccountRestakingConfig extends string | IAccountMeta = string, + TAccountNcn extends string | IAccountMeta = string, + TAccountOperator extends string | IAccountMeta = string, + TAccountNcnOperatorState extends string | IAccountMeta = string, + TAccountEpochSnapshot extends string | IAccountMeta = string, + TAccountOperatorSnapshot extends string | IAccountMeta = string, + TAccountPayer extends string | IAccountMeta = string, + TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountSystemProgram extends + | string + | IAccountMeta = '11111111111111111111111111111111', + TRemainingAccounts extends readonly IAccountMeta[] = [], +> = IInstruction & + IInstructionWithData & + IInstructionWithAccounts< + [ + TAccountNcnConfig extends string + ? ReadonlyAccount + : TAccountNcnConfig, + TAccountRestakingConfig extends string + ? ReadonlyAccount + : TAccountRestakingConfig, + TAccountNcn extends string ? ReadonlyAccount : TAccountNcn, + TAccountOperator extends string + ? ReadonlyAccount + : TAccountOperator, + TAccountNcnOperatorState extends string + ? ReadonlyAccount + : TAccountNcnOperatorState, + TAccountEpochSnapshot extends string + ? WritableAccount + : TAccountEpochSnapshot, + TAccountOperatorSnapshot extends string + ? WritableAccount + : TAccountOperatorSnapshot, + TAccountPayer extends string + ? WritableSignerAccount & + IAccountSignerMeta + : TAccountPayer, + TAccountRestakingProgramId extends string + ? ReadonlyAccount + : TAccountRestakingProgramId, + TAccountSystemProgram extends string + ? ReadonlyAccount + : TAccountSystemProgram, + ...TRemainingAccounts, + ] + >; + +export type InitializeOperatorSnapshotInstructionData = { + discriminator: number; + firstSlotOfNcnEpoch: Option; +}; + +export type InitializeOperatorSnapshotInstructionDataArgs = { + firstSlotOfNcnEpoch: OptionOrNullable; +}; + +export function getInitializeOperatorSnapshotInstructionDataEncoder(): Encoder { + return transformEncoder( + getStructEncoder([ + ['discriminator', getU8Encoder()], + ['firstSlotOfNcnEpoch', getOptionEncoder(getU64Encoder())], + ]), + (value) => ({ + ...value, + discriminator: INITIALIZE_OPERATOR_SNAPSHOT_DISCRIMINATOR, + }) + ); +} + +export function getInitializeOperatorSnapshotInstructionDataDecoder(): Decoder { + return getStructDecoder([ + ['discriminator', getU8Decoder()], + ['firstSlotOfNcnEpoch', getOptionDecoder(getU64Decoder())], + ]); +} + +export function getInitializeOperatorSnapshotInstructionDataCodec(): Codec< + InitializeOperatorSnapshotInstructionDataArgs, + InitializeOperatorSnapshotInstructionData +> { + return combineCodec( + getInitializeOperatorSnapshotInstructionDataEncoder(), + getInitializeOperatorSnapshotInstructionDataDecoder() + ); +} + +export type InitializeOperatorSnapshotInput< + TAccountNcnConfig extends string = string, + TAccountRestakingConfig extends string = string, + TAccountNcn extends string = string, + TAccountOperator extends string = string, + TAccountNcnOperatorState extends string = string, + TAccountEpochSnapshot extends string = string, + TAccountOperatorSnapshot extends string = string, + TAccountPayer extends string = string, + TAccountRestakingProgramId extends string = string, + TAccountSystemProgram extends string = string, +> = { + ncnConfig: Address; + restakingConfig: Address; + ncn: Address; + operator: Address; + ncnOperatorState: Address; + epochSnapshot: Address; + operatorSnapshot: Address; + payer: TransactionSigner; + restakingProgramId: Address; + systemProgram?: Address; + firstSlotOfNcnEpoch: InitializeOperatorSnapshotInstructionDataArgs['firstSlotOfNcnEpoch']; +}; + +export function getInitializeOperatorSnapshotInstruction< + TAccountNcnConfig extends string, + TAccountRestakingConfig extends string, + TAccountNcn extends string, + TAccountOperator extends string, + TAccountNcnOperatorState extends string, + TAccountEpochSnapshot extends string, + TAccountOperatorSnapshot extends string, + TAccountPayer extends string, + TAccountRestakingProgramId extends string, + TAccountSystemProgram extends string, + TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, +>( + input: InitializeOperatorSnapshotInput< + TAccountNcnConfig, + TAccountRestakingConfig, + TAccountNcn, + TAccountOperator, + TAccountNcnOperatorState, + TAccountEpochSnapshot, + TAccountOperatorSnapshot, + TAccountPayer, + TAccountRestakingProgramId, + TAccountSystemProgram + >, + config?: { programAddress?: TProgramAddress } +): InitializeOperatorSnapshotInstruction< + TProgramAddress, + TAccountNcnConfig, + TAccountRestakingConfig, + TAccountNcn, + TAccountOperator, + TAccountNcnOperatorState, + TAccountEpochSnapshot, + TAccountOperatorSnapshot, + TAccountPayer, + TAccountRestakingProgramId, + TAccountSystemProgram +> { + // Program address. + const programAddress = + config?.programAddress ?? JITO_TIP_ROUTER_PROGRAM_ADDRESS; + + // Original accounts. + const originalAccounts = { + ncnConfig: { value: input.ncnConfig ?? null, isWritable: false }, + restakingConfig: { + value: input.restakingConfig ?? null, + isWritable: false, + }, + ncn: { value: input.ncn ?? null, isWritable: false }, + operator: { value: input.operator ?? null, isWritable: false }, + ncnOperatorState: { + value: input.ncnOperatorState ?? null, + isWritable: false, + }, + epochSnapshot: { value: input.epochSnapshot ?? null, isWritable: true }, + operatorSnapshot: { + value: input.operatorSnapshot ?? null, + isWritable: true, + }, + payer: { value: input.payer ?? null, isWritable: true }, + restakingProgramId: { + value: input.restakingProgramId ?? null, + isWritable: false, + }, + systemProgram: { value: input.systemProgram ?? null, isWritable: false }, + }; + const accounts = originalAccounts as Record< + keyof typeof originalAccounts, + ResolvedAccount + >; + + // Original args. + const args = { ...input }; + + // Resolve default values. + if (!accounts.systemProgram.value) { + accounts.systemProgram.value = + '11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>; + } + + const getAccountMeta = getAccountMetaFactory(programAddress, 'programId'); + const instruction = { + accounts: [ + getAccountMeta(accounts.ncnConfig), + getAccountMeta(accounts.restakingConfig), + getAccountMeta(accounts.ncn), + getAccountMeta(accounts.operator), + getAccountMeta(accounts.ncnOperatorState), + getAccountMeta(accounts.epochSnapshot), + getAccountMeta(accounts.operatorSnapshot), + getAccountMeta(accounts.payer), + getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.systemProgram), + ], + programAddress, + data: getInitializeOperatorSnapshotInstructionDataEncoder().encode( + args as InitializeOperatorSnapshotInstructionDataArgs + ), + } as InitializeOperatorSnapshotInstruction< + TProgramAddress, + TAccountNcnConfig, + TAccountRestakingConfig, + TAccountNcn, + TAccountOperator, + TAccountNcnOperatorState, + TAccountEpochSnapshot, + TAccountOperatorSnapshot, + TAccountPayer, + TAccountRestakingProgramId, + TAccountSystemProgram + >; + + return instruction; +} + +export type ParsedInitializeOperatorSnapshotInstruction< + TProgram extends string = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, + TAccountMetas extends readonly IAccountMeta[] = readonly IAccountMeta[], +> = { + programAddress: Address; + accounts: { + ncnConfig: TAccountMetas[0]; + restakingConfig: TAccountMetas[1]; + ncn: TAccountMetas[2]; + operator: TAccountMetas[3]; + ncnOperatorState: TAccountMetas[4]; + epochSnapshot: TAccountMetas[5]; + operatorSnapshot: TAccountMetas[6]; + payer: TAccountMetas[7]; + restakingProgramId: TAccountMetas[8]; + systemProgram: TAccountMetas[9]; + }; + data: InitializeOperatorSnapshotInstructionData; +}; + +export function parseInitializeOperatorSnapshotInstruction< + TProgram extends string, + TAccountMetas extends readonly IAccountMeta[], +>( + instruction: IInstruction & + IInstructionWithAccounts & + IInstructionWithData +): ParsedInitializeOperatorSnapshotInstruction { + if (instruction.accounts.length < 10) { + // TODO: Coded error. + throw new Error('Not enough accounts'); + } + let accountIndex = 0; + const getNextAccount = () => { + const accountMeta = instruction.accounts![accountIndex]!; + accountIndex += 1; + return accountMeta; + }; + return { + programAddress: instruction.programAddress, + accounts: { + ncnConfig: getNextAccount(), + restakingConfig: getNextAccount(), + ncn: getNextAccount(), + operator: getNextAccount(), + ncnOperatorState: getNextAccount(), + epochSnapshot: getNextAccount(), + operatorSnapshot: getNextAccount(), + payer: getNextAccount(), + restakingProgramId: getNextAccount(), + systemProgram: getNextAccount(), + }, + data: getInitializeOperatorSnapshotInstructionDataDecoder().decode( + instruction.data + ), + }; +} diff --git a/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts b/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts new file mode 100644 index 0000000..9416e77 --- /dev/null +++ b/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts @@ -0,0 +1,417 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/kinobi-so/kinobi + */ + +import { + combineCodec, + getOptionDecoder, + getOptionEncoder, + getStructDecoder, + getStructEncoder, + getU64Decoder, + getU64Encoder, + getU8Decoder, + getU8Encoder, + transformEncoder, + type Address, + type Codec, + type Decoder, + type Encoder, + type IAccountMeta, + type IAccountSignerMeta, + type IInstruction, + type IInstructionWithAccounts, + type IInstructionWithData, + type Option, + type OptionOrNullable, + type ReadonlyAccount, + type TransactionSigner, + type WritableAccount, + type WritableSignerAccount, +} from '@solana/web3.js'; +import { JITO_TIP_ROUTER_PROGRAM_ADDRESS } from '../programs'; +import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; + +export const INITIALIZE_VAULT_OPERATOR_DELEGATION_SNAPSHOT_DISCRIMINATOR = 7; + +export function getInitializeVaultOperatorDelegationSnapshotDiscriminatorBytes() { + return getU8Encoder().encode( + INITIALIZE_VAULT_OPERATOR_DELEGATION_SNAPSHOT_DISCRIMINATOR + ); +} + +export type InitializeVaultOperatorDelegationSnapshotInstruction< + TProgram extends string = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, + TAccountNcnConfig extends string | IAccountMeta = string, + TAccountRestakingConfig extends string | IAccountMeta = string, + TAccountNcn extends string | IAccountMeta = string, + TAccountOperator extends string | IAccountMeta = string, + TAccountVault extends string | IAccountMeta = string, + TAccountVaultNcnTicket extends string | IAccountMeta = string, + TAccountNcnVaultTicket extends string | IAccountMeta = string, + TAccountVaultOperatorDelegation extends + | string + | IAccountMeta = string, + TAccountWeightTable extends string | IAccountMeta = string, + TAccountEpochSnapshot extends string | IAccountMeta = string, + TAccountOperatorSnapshot extends string | IAccountMeta = string, + TAccountVaultOperatorDelegationSnapshot extends + | string + | IAccountMeta = string, + TAccountPayer extends string | IAccountMeta = string, + TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountSystemProgram extends + | string + | IAccountMeta = '11111111111111111111111111111111', + TRemainingAccounts extends readonly IAccountMeta[] = [], +> = IInstruction & + IInstructionWithData & + IInstructionWithAccounts< + [ + TAccountNcnConfig extends string + ? ReadonlyAccount + : TAccountNcnConfig, + TAccountRestakingConfig extends string + ? ReadonlyAccount + : TAccountRestakingConfig, + TAccountNcn extends string ? ReadonlyAccount : TAccountNcn, + TAccountOperator extends string + ? ReadonlyAccount + : TAccountOperator, + TAccountVault extends string + ? ReadonlyAccount + : TAccountVault, + TAccountVaultNcnTicket extends string + ? ReadonlyAccount + : TAccountVaultNcnTicket, + TAccountNcnVaultTicket extends string + ? ReadonlyAccount + : TAccountNcnVaultTicket, + TAccountVaultOperatorDelegation extends string + ? ReadonlyAccount + : TAccountVaultOperatorDelegation, + TAccountWeightTable extends string + ? ReadonlyAccount + : TAccountWeightTable, + TAccountEpochSnapshot extends string + ? WritableAccount + : TAccountEpochSnapshot, + TAccountOperatorSnapshot extends string + ? WritableAccount + : TAccountOperatorSnapshot, + TAccountVaultOperatorDelegationSnapshot extends string + ? WritableAccount + : TAccountVaultOperatorDelegationSnapshot, + TAccountPayer extends string + ? WritableSignerAccount & + IAccountSignerMeta + : TAccountPayer, + TAccountRestakingProgramId extends string + ? ReadonlyAccount + : TAccountRestakingProgramId, + TAccountSystemProgram extends string + ? ReadonlyAccount + : TAccountSystemProgram, + ...TRemainingAccounts, + ] + >; + +export type InitializeVaultOperatorDelegationSnapshotInstructionData = { + discriminator: number; + firstSlotOfNcnEpoch: Option; +}; + +export type InitializeVaultOperatorDelegationSnapshotInstructionDataArgs = { + firstSlotOfNcnEpoch: OptionOrNullable; +}; + +export function getInitializeVaultOperatorDelegationSnapshotInstructionDataEncoder(): Encoder { + return transformEncoder( + getStructEncoder([ + ['discriminator', getU8Encoder()], + ['firstSlotOfNcnEpoch', getOptionEncoder(getU64Encoder())], + ]), + (value) => ({ + ...value, + discriminator: + INITIALIZE_VAULT_OPERATOR_DELEGATION_SNAPSHOT_DISCRIMINATOR, + }) + ); +} + +export function getInitializeVaultOperatorDelegationSnapshotInstructionDataDecoder(): Decoder { + return getStructDecoder([ + ['discriminator', getU8Decoder()], + ['firstSlotOfNcnEpoch', getOptionDecoder(getU64Decoder())], + ]); +} + +export function getInitializeVaultOperatorDelegationSnapshotInstructionDataCodec(): Codec< + InitializeVaultOperatorDelegationSnapshotInstructionDataArgs, + InitializeVaultOperatorDelegationSnapshotInstructionData +> { + return combineCodec( + getInitializeVaultOperatorDelegationSnapshotInstructionDataEncoder(), + getInitializeVaultOperatorDelegationSnapshotInstructionDataDecoder() + ); +} + +export type InitializeVaultOperatorDelegationSnapshotInput< + TAccountNcnConfig extends string = string, + TAccountRestakingConfig extends string = string, + TAccountNcn extends string = string, + TAccountOperator extends string = string, + TAccountVault extends string = string, + TAccountVaultNcnTicket extends string = string, + TAccountNcnVaultTicket extends string = string, + TAccountVaultOperatorDelegation extends string = string, + TAccountWeightTable extends string = string, + TAccountEpochSnapshot extends string = string, + TAccountOperatorSnapshot extends string = string, + TAccountVaultOperatorDelegationSnapshot extends string = string, + TAccountPayer extends string = string, + TAccountRestakingProgramId extends string = string, + TAccountSystemProgram extends string = string, +> = { + ncnConfig: Address; + restakingConfig: Address; + ncn: Address; + operator: Address; + vault: Address; + vaultNcnTicket: Address; + ncnVaultTicket: Address; + vaultOperatorDelegation: Address; + weightTable: Address; + epochSnapshot: Address; + operatorSnapshot: Address; + vaultOperatorDelegationSnapshot: Address; + payer: TransactionSigner; + restakingProgramId: Address; + systemProgram?: Address; + firstSlotOfNcnEpoch: InitializeVaultOperatorDelegationSnapshotInstructionDataArgs['firstSlotOfNcnEpoch']; +}; + +export function getInitializeVaultOperatorDelegationSnapshotInstruction< + TAccountNcnConfig extends string, + TAccountRestakingConfig extends string, + TAccountNcn extends string, + TAccountOperator extends string, + TAccountVault extends string, + TAccountVaultNcnTicket extends string, + TAccountNcnVaultTicket extends string, + TAccountVaultOperatorDelegation extends string, + TAccountWeightTable extends string, + TAccountEpochSnapshot extends string, + TAccountOperatorSnapshot extends string, + TAccountVaultOperatorDelegationSnapshot extends string, + TAccountPayer extends string, + TAccountRestakingProgramId extends string, + TAccountSystemProgram extends string, + TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, +>( + input: InitializeVaultOperatorDelegationSnapshotInput< + TAccountNcnConfig, + TAccountRestakingConfig, + TAccountNcn, + TAccountOperator, + TAccountVault, + TAccountVaultNcnTicket, + TAccountNcnVaultTicket, + TAccountVaultOperatorDelegation, + TAccountWeightTable, + TAccountEpochSnapshot, + TAccountOperatorSnapshot, + TAccountVaultOperatorDelegationSnapshot, + TAccountPayer, + TAccountRestakingProgramId, + TAccountSystemProgram + >, + config?: { programAddress?: TProgramAddress } +): InitializeVaultOperatorDelegationSnapshotInstruction< + TProgramAddress, + TAccountNcnConfig, + TAccountRestakingConfig, + TAccountNcn, + TAccountOperator, + TAccountVault, + TAccountVaultNcnTicket, + TAccountNcnVaultTicket, + TAccountVaultOperatorDelegation, + TAccountWeightTable, + TAccountEpochSnapshot, + TAccountOperatorSnapshot, + TAccountVaultOperatorDelegationSnapshot, + TAccountPayer, + TAccountRestakingProgramId, + TAccountSystemProgram +> { + // Program address. + const programAddress = + config?.programAddress ?? JITO_TIP_ROUTER_PROGRAM_ADDRESS; + + // Original accounts. + const originalAccounts = { + ncnConfig: { value: input.ncnConfig ?? null, isWritable: false }, + restakingConfig: { + value: input.restakingConfig ?? null, + isWritable: false, + }, + ncn: { value: input.ncn ?? null, isWritable: false }, + operator: { value: input.operator ?? null, isWritable: false }, + vault: { value: input.vault ?? null, isWritable: false }, + vaultNcnTicket: { value: input.vaultNcnTicket ?? null, isWritable: false }, + ncnVaultTicket: { value: input.ncnVaultTicket ?? null, isWritable: false }, + vaultOperatorDelegation: { + value: input.vaultOperatorDelegation ?? null, + isWritable: false, + }, + weightTable: { value: input.weightTable ?? null, isWritable: false }, + epochSnapshot: { value: input.epochSnapshot ?? null, isWritable: true }, + operatorSnapshot: { + value: input.operatorSnapshot ?? null, + isWritable: true, + }, + vaultOperatorDelegationSnapshot: { + value: input.vaultOperatorDelegationSnapshot ?? null, + isWritable: true, + }, + payer: { value: input.payer ?? null, isWritable: true }, + restakingProgramId: { + value: input.restakingProgramId ?? null, + isWritable: false, + }, + systemProgram: { value: input.systemProgram ?? null, isWritable: false }, + }; + const accounts = originalAccounts as Record< + keyof typeof originalAccounts, + ResolvedAccount + >; + + // Original args. + const args = { ...input }; + + // Resolve default values. + if (!accounts.systemProgram.value) { + accounts.systemProgram.value = + '11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>; + } + + const getAccountMeta = getAccountMetaFactory(programAddress, 'programId'); + const instruction = { + accounts: [ + getAccountMeta(accounts.ncnConfig), + getAccountMeta(accounts.restakingConfig), + getAccountMeta(accounts.ncn), + getAccountMeta(accounts.operator), + getAccountMeta(accounts.vault), + getAccountMeta(accounts.vaultNcnTicket), + getAccountMeta(accounts.ncnVaultTicket), + getAccountMeta(accounts.vaultOperatorDelegation), + getAccountMeta(accounts.weightTable), + getAccountMeta(accounts.epochSnapshot), + getAccountMeta(accounts.operatorSnapshot), + getAccountMeta(accounts.vaultOperatorDelegationSnapshot), + getAccountMeta(accounts.payer), + getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.systemProgram), + ], + programAddress, + data: getInitializeVaultOperatorDelegationSnapshotInstructionDataEncoder().encode( + args as InitializeVaultOperatorDelegationSnapshotInstructionDataArgs + ), + } as InitializeVaultOperatorDelegationSnapshotInstruction< + TProgramAddress, + TAccountNcnConfig, + TAccountRestakingConfig, + TAccountNcn, + TAccountOperator, + TAccountVault, + TAccountVaultNcnTicket, + TAccountNcnVaultTicket, + TAccountVaultOperatorDelegation, + TAccountWeightTable, + TAccountEpochSnapshot, + TAccountOperatorSnapshot, + TAccountVaultOperatorDelegationSnapshot, + TAccountPayer, + TAccountRestakingProgramId, + TAccountSystemProgram + >; + + return instruction; +} + +export type ParsedInitializeVaultOperatorDelegationSnapshotInstruction< + TProgram extends string = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, + TAccountMetas extends readonly IAccountMeta[] = readonly IAccountMeta[], +> = { + programAddress: Address; + accounts: { + ncnConfig: TAccountMetas[0]; + restakingConfig: TAccountMetas[1]; + ncn: TAccountMetas[2]; + operator: TAccountMetas[3]; + vault: TAccountMetas[4]; + vaultNcnTicket: TAccountMetas[5]; + ncnVaultTicket: TAccountMetas[6]; + vaultOperatorDelegation: TAccountMetas[7]; + weightTable: TAccountMetas[8]; + epochSnapshot: TAccountMetas[9]; + operatorSnapshot: TAccountMetas[10]; + vaultOperatorDelegationSnapshot: TAccountMetas[11]; + payer: TAccountMetas[12]; + restakingProgramId: TAccountMetas[13]; + systemProgram: TAccountMetas[14]; + }; + data: InitializeVaultOperatorDelegationSnapshotInstructionData; +}; + +export function parseInitializeVaultOperatorDelegationSnapshotInstruction< + TProgram extends string, + TAccountMetas extends readonly IAccountMeta[], +>( + instruction: IInstruction & + IInstructionWithAccounts & + IInstructionWithData +): ParsedInitializeVaultOperatorDelegationSnapshotInstruction< + TProgram, + TAccountMetas +> { + if (instruction.accounts.length < 15) { + // TODO: Coded error. + throw new Error('Not enough accounts'); + } + let accountIndex = 0; + const getNextAccount = () => { + const accountMeta = instruction.accounts![accountIndex]!; + accountIndex += 1; + return accountMeta; + }; + return { + programAddress: instruction.programAddress, + accounts: { + ncnConfig: getNextAccount(), + restakingConfig: getNextAccount(), + ncn: getNextAccount(), + operator: getNextAccount(), + vault: getNextAccount(), + vaultNcnTicket: getNextAccount(), + ncnVaultTicket: getNextAccount(), + vaultOperatorDelegation: getNextAccount(), + weightTable: getNextAccount(), + epochSnapshot: getNextAccount(), + operatorSnapshot: getNextAccount(), + vaultOperatorDelegationSnapshot: getNextAccount(), + payer: getNextAccount(), + restakingProgramId: getNextAccount(), + systemProgram: getNextAccount(), + }, + data: getInitializeVaultOperatorDelegationSnapshotInstructionDataDecoder().decode( + instruction.data + ), + }; +} diff --git a/clients/js/jito_tip_router/programs/jitoTipRouter.ts b/clients/js/jito_tip_router/programs/jitoTipRouter.ts index f23e413..8ab4386 100644 --- a/clients/js/jito_tip_router/programs/jitoTipRouter.ts +++ b/clients/js/jito_tip_router/programs/jitoTipRouter.ts @@ -16,6 +16,8 @@ import { type ParsedAdminUpdateWeightTableInstruction, type ParsedInitializeEpochSnapshotInstruction, type ParsedInitializeNCNConfigInstruction, + type ParsedInitializeOperatorSnapshotInstruction, + type ParsedInitializeVaultOperatorDelegationSnapshotInstruction, type ParsedInitializeWeightTableInstruction, type ParsedSetConfigFeesInstruction, type ParsedSetNewAdminInstruction, @@ -27,6 +29,7 @@ export const JITO_TIP_ROUTER_PROGRAM_ADDRESS = export enum JitoTipRouterAccount { EpochSnapshot, OperatorSnapshot, + VaultOperatorDelegationSnapshot, NcnConfig, WeightTable, } @@ -38,6 +41,8 @@ export enum JitoTipRouterInstruction { InitializeWeightTable, AdminUpdateWeightTable, InitializeEpochSnapshot, + InitializeOperatorSnapshot, + InitializeVaultOperatorDelegationSnapshot, } export function identifyJitoTipRouterInstruction( @@ -62,6 +67,12 @@ export function identifyJitoTipRouterInstruction( if (containsBytes(data, getU8Encoder().encode(5), 0)) { return JitoTipRouterInstruction.InitializeEpochSnapshot; } + if (containsBytes(data, getU8Encoder().encode(6), 0)) { + return JitoTipRouterInstruction.InitializeOperatorSnapshot; + } + if (containsBytes(data, getU8Encoder().encode(7), 0)) { + return JitoTipRouterInstruction.InitializeVaultOperatorDelegationSnapshot; + } throw new Error( 'The provided instruction could not be identified as a jitoTipRouter instruction.' ); @@ -87,4 +98,10 @@ export type ParsedJitoTipRouterInstruction< } & ParsedAdminUpdateWeightTableInstruction) | ({ instructionType: JitoTipRouterInstruction.InitializeEpochSnapshot; - } & ParsedInitializeEpochSnapshotInstruction); + } & ParsedInitializeEpochSnapshotInstruction) + | ({ + instructionType: JitoTipRouterInstruction.InitializeOperatorSnapshot; + } & ParsedInitializeOperatorSnapshotInstruction) + | ({ + instructionType: JitoTipRouterInstruction.InitializeVaultOperatorDelegationSnapshot; + } & ParsedInitializeVaultOperatorDelegationSnapshotInstruction); diff --git a/clients/js/jito_tip_router/types/index.ts b/clients/js/jito_tip_router/types/index.ts index dd0513a..a78e605 100644 --- a/clients/js/jito_tip_router/types/index.ts +++ b/clients/js/jito_tip_router/types/index.ts @@ -9,5 +9,4 @@ export * from './configAdminRole'; export * from './fee'; export * from './fees'; -export * from './vaultOperatorDelegationSnapshot'; export * from './weightEntry'; diff --git a/clients/js/jito_tip_router/types/vaultOperatorDelegationSnapshot.ts b/clients/js/jito_tip_router/types/vaultOperatorDelegationSnapshot.ts deleted file mode 100644 index 22529c7..0000000 --- a/clients/js/jito_tip_router/types/vaultOperatorDelegationSnapshot.ts +++ /dev/null @@ -1,77 +0,0 @@ -/** - * This code was AUTOGENERATED using the kinobi library. - * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. - * - * @see https://github.com/kinobi-so/kinobi - */ - -import { - combineCodec, - getAddressDecoder, - getAddressEncoder, - getArrayDecoder, - getArrayEncoder, - getStructDecoder, - getStructEncoder, - getU128Decoder, - getU128Encoder, - getU64Decoder, - getU64Encoder, - getU8Decoder, - getU8Encoder, - type Address, - type Codec, - type Decoder, - type Encoder, -} from '@solana/web3.js'; - -export type VaultOperatorDelegationSnapshot = { - vault: Address; - stMint: Address; - totalSecurity: bigint; - totalVotes: bigint; - slotSet: bigint; - reserved: Array; -}; - -export type VaultOperatorDelegationSnapshotArgs = { - vault: Address; - stMint: Address; - totalSecurity: number | bigint; - totalVotes: number | bigint; - slotSet: number | bigint; - reserved: Array; -}; - -export function getVaultOperatorDelegationSnapshotEncoder(): Encoder { - return getStructEncoder([ - ['vault', getAddressEncoder()], - ['stMint', getAddressEncoder()], - ['totalSecurity', getU64Encoder()], - ['totalVotes', getU128Encoder()], - ['slotSet', getU64Encoder()], - ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], - ]); -} - -export function getVaultOperatorDelegationSnapshotDecoder(): Decoder { - return getStructDecoder([ - ['vault', getAddressDecoder()], - ['stMint', getAddressDecoder()], - ['totalSecurity', getU64Decoder()], - ['totalVotes', getU128Decoder()], - ['slotSet', getU64Decoder()], - ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], - ]); -} - -export function getVaultOperatorDelegationSnapshotCodec(): Codec< - VaultOperatorDelegationSnapshotArgs, - VaultOperatorDelegationSnapshot -> { - return combineCodec( - getVaultOperatorDelegationSnapshotEncoder(), - getVaultOperatorDelegationSnapshotDecoder() - ); -} diff --git a/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs b/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs index da51aeb..20a1e24 100644 --- a/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs @@ -19,11 +19,13 @@ pub struct EpochSnapshot { )] pub ncn: Pubkey, pub ncn_epoch: u64, - pub slot_created: u64, pub bump: u8, + pub slot_created: u64, + pub slot_finalized: u64, pub ncn_fees: Fees, pub operator_count: u64, pub operators_registered: u64, + pub valid_operator_vault_delegations: u64, pub total_votes: u128, #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] pub reserved: [u8; 128], diff --git a/clients/rust/jito_tip_router/src/generated/accounts/mod.rs b/clients/rust/jito_tip_router/src/generated/accounts/mod.rs index 4655dd2..6cdf26e 100644 --- a/clients/rust/jito_tip_router/src/generated/accounts/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/accounts/mod.rs @@ -7,6 +7,10 @@ pub(crate) mod r#epoch_snapshot; pub(crate) mod r#ncn_config; pub(crate) mod r#operator_snapshot; +pub(crate) mod r#vault_operator_delegation_snapshot; pub(crate) mod r#weight_table; -pub use self::{r#epoch_snapshot::*, r#ncn_config::*, r#operator_snapshot::*, r#weight_table::*}; +pub use self::{ + r#epoch_snapshot::*, r#ncn_config::*, r#operator_snapshot::*, + r#vault_operator_delegation_snapshot::*, r#weight_table::*, +}; diff --git a/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs b/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs index 80038f5..988e4f1 100644 --- a/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs @@ -7,8 +7,6 @@ use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::pubkey::Pubkey; -use crate::generated::types::VaultOperatorDelegationSnapshot; - #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct OperatorSnapshot { @@ -24,14 +22,15 @@ pub struct OperatorSnapshot { )] pub ncn: Pubkey, pub ncn_epoch: u64, - pub slot_created: u64, pub bump: u8, + pub slot_created: u64, + pub slot_finalized: u64, + pub is_active: bool, pub operator_fee_bps: u16, + pub vault_operator_delegation_count: u64, + pub vault_operator_delegations_registered: u64, + pub valid_operator_vault_delegations: u64, pub total_votes: u128, - pub num_vault_operator_delegations: u16, - pub vault_operator_delegations_registered: u16, - pub slot_set: u64, - pub vault_operator_delegations: [VaultOperatorDelegationSnapshot; 32], #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] pub reserved: [u8; 128], } diff --git a/clients/rust/jito_tip_router/src/generated/accounts/vault_operator_delegation_snapshot.rs b/clients/rust/jito_tip_router/src/generated/accounts/vault_operator_delegation_snapshot.rs new file mode 100644 index 0000000..c33af9c --- /dev/null +++ b/clients/rust/jito_tip_router/src/generated/accounts/vault_operator_delegation_snapshot.rs @@ -0,0 +1,88 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! + +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct VaultOperatorDelegationSnapshot { + pub discriminator: u64, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub vault: Pubkey, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub operator: Pubkey, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub ncn: Pubkey, + pub ncn_epoch: u64, + pub bump: u8, + pub slot_created: u64, + pub is_active: bool, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub st_mint: Pubkey, + pub total_security: u64, + pub total_votes: u128, + #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] + pub reserved: [u8; 128], +} + +impl VaultOperatorDelegationSnapshot { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> + for VaultOperatorDelegationSnapshot +{ + type Error = std::io::Error; + + fn try_from( + account_info: &solana_program::account_info::AccountInfo<'a>, + ) -> Result { + let mut data: &[u8] = &(*account_info.data).borrow(); + Self::deserialize(&mut data) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for VaultOperatorDelegationSnapshot { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for VaultOperatorDelegationSnapshot {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for VaultOperatorDelegationSnapshot { + fn owner() -> Pubkey { + crate::JITO_TIP_ROUTER_ID + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for VaultOperatorDelegationSnapshot {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for VaultOperatorDelegationSnapshot { + const DISCRIMINATOR: [u8; 8] = [0; 8]; +} diff --git a/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs b/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs index efaa971..65ac98f 100644 --- a/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs +++ b/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs @@ -69,6 +69,15 @@ pub enum JitoTipRouterError { /// 8718 - Weight not found #[error("Weight not found")] WeightNotFound = 0x220E, + /// 8719 - No operators in ncn + #[error("No operators in ncn")] + NoOperators = 0x220F, + /// 8720 - Vault operator delegation is already finalized - should not happen + #[error("Vault operator delegation is already finalized - should not happen")] + VaultOperatorDelegationFinalized = 0x2210, + /// 8721 - Operator is already finalized - should not happen + #[error("Operator is already finalized - should not happen")] + OperatorFinalized = 0x2211, } impl solana_program::program_error::PrintProgramError for JitoTipRouterError { diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_operator_snapshot.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_operator_snapshot.rs new file mode 100644 index 0000000..c367681 --- /dev/null +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_operator_snapshot.rs @@ -0,0 +1,692 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! + +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct InitializeOperatorSnapshot { + pub ncn_config: solana_program::pubkey::Pubkey, + + pub restaking_config: solana_program::pubkey::Pubkey, + + pub ncn: solana_program::pubkey::Pubkey, + + pub operator: solana_program::pubkey::Pubkey, + + pub ncn_operator_state: solana_program::pubkey::Pubkey, + + pub epoch_snapshot: solana_program::pubkey::Pubkey, + + pub operator_snapshot: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub restaking_program_id: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl InitializeOperatorSnapshot { + pub fn instruction( + &self, + args: InitializeOperatorSnapshotInstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: InitializeOperatorSnapshotInstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(10 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.ncn_config, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.restaking_config, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.ncn, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.operator, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.ncn_operator_state, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.epoch_snapshot, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.operator_snapshot, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.restaking_program_id, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = InitializeOperatorSnapshotInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::JITO_TIP_ROUTER_ID, + accounts, + data, + } + } +} + +#[derive(BorshDeserialize, BorshSerialize)] +pub struct InitializeOperatorSnapshotInstructionData { + discriminator: u8, +} + +impl InitializeOperatorSnapshotInstructionData { + pub fn new() -> Self { + Self { discriminator: 6 } + } +} + +impl Default for InitializeOperatorSnapshotInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct InitializeOperatorSnapshotInstructionArgs { + pub first_slot_of_ncn_epoch: Option, +} + +/// Instruction builder for `InitializeOperatorSnapshot`. +/// +/// ### Accounts: +/// +/// 0. `[]` ncn_config +/// 1. `[]` restaking_config +/// 2. `[]` ncn +/// 3. `[]` operator +/// 4. `[]` ncn_operator_state +/// 5. `[writable]` epoch_snapshot +/// 6. `[writable]` operator_snapshot +/// 7. `[writable, signer]` payer +/// 8. `[]` restaking_program_id +/// 9. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct InitializeOperatorSnapshotBuilder { + ncn_config: Option, + restaking_config: Option, + ncn: Option, + operator: Option, + ncn_operator_state: Option, + epoch_snapshot: Option, + operator_snapshot: Option, + payer: Option, + restaking_program_id: Option, + system_program: Option, + first_slot_of_ncn_epoch: Option, + __remaining_accounts: Vec, +} + +impl InitializeOperatorSnapshotBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn ncn_config(&mut self, ncn_config: solana_program::pubkey::Pubkey) -> &mut Self { + self.ncn_config = Some(ncn_config); + self + } + #[inline(always)] + pub fn restaking_config( + &mut self, + restaking_config: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.restaking_config = Some(restaking_config); + self + } + #[inline(always)] + pub fn ncn(&mut self, ncn: solana_program::pubkey::Pubkey) -> &mut Self { + self.ncn = Some(ncn); + self + } + #[inline(always)] + pub fn operator(&mut self, operator: solana_program::pubkey::Pubkey) -> &mut Self { + self.operator = Some(operator); + self + } + #[inline(always)] + pub fn ncn_operator_state( + &mut self, + ncn_operator_state: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.ncn_operator_state = Some(ncn_operator_state); + self + } + #[inline(always)] + pub fn epoch_snapshot(&mut self, epoch_snapshot: solana_program::pubkey::Pubkey) -> &mut Self { + self.epoch_snapshot = Some(epoch_snapshot); + self + } + #[inline(always)] + pub fn operator_snapshot( + &mut self, + operator_snapshot: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.operator_snapshot = Some(operator_snapshot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + #[inline(always)] + pub fn restaking_program_id( + &mut self, + restaking_program_id: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.restaking_program_id = Some(restaking_program_id); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn first_slot_of_ncn_epoch(&mut self, first_slot_of_ncn_epoch: u64) -> &mut Self { + self.first_slot_of_ncn_epoch = Some(first_slot_of_ncn_epoch); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = InitializeOperatorSnapshot { + ncn_config: self.ncn_config.expect("ncn_config is not set"), + restaking_config: self.restaking_config.expect("restaking_config is not set"), + ncn: self.ncn.expect("ncn is not set"), + operator: self.operator.expect("operator is not set"), + ncn_operator_state: self + .ncn_operator_state + .expect("ncn_operator_state is not set"), + epoch_snapshot: self.epoch_snapshot.expect("epoch_snapshot is not set"), + operator_snapshot: self + .operator_snapshot + .expect("operator_snapshot is not set"), + payer: self.payer.expect("payer is not set"), + restaking_program_id: self + .restaking_program_id + .expect("restaking_program_id is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = InitializeOperatorSnapshotInstructionArgs { + first_slot_of_ncn_epoch: self.first_slot_of_ncn_epoch.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `initialize_operator_snapshot` CPI accounts. +pub struct InitializeOperatorSnapshotCpiAccounts<'a, 'b> { + pub ncn_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn: &'b solana_program::account_info::AccountInfo<'a>, + + pub operator: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn_operator_state: &'b solana_program::account_info::AccountInfo<'a>, + + pub epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub operator_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `initialize_operator_snapshot` CPI instruction. +pub struct InitializeOperatorSnapshotCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn: &'b solana_program::account_info::AccountInfo<'a>, + + pub operator: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn_operator_state: &'b solana_program::account_info::AccountInfo<'a>, + + pub epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub operator_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: InitializeOperatorSnapshotInstructionArgs, +} + +impl<'a, 'b> InitializeOperatorSnapshotCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: InitializeOperatorSnapshotCpiAccounts<'a, 'b>, + args: InitializeOperatorSnapshotInstructionArgs, + ) -> Self { + Self { + __program: program, + ncn_config: accounts.ncn_config, + restaking_config: accounts.restaking_config, + ncn: accounts.ncn, + operator: accounts.operator, + ncn_operator_state: accounts.ncn_operator_state, + epoch_snapshot: accounts.epoch_snapshot, + operator_snapshot: accounts.operator_snapshot, + payer: accounts.payer, + restaking_program_id: accounts.restaking_program_id, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(10 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.ncn_config.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.restaking_config.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.ncn.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.operator.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.ncn_operator_state.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.epoch_snapshot.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.operator_snapshot.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.restaking_program_id.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = InitializeOperatorSnapshotInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::JITO_TIP_ROUTER_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(10 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.ncn_config.clone()); + account_infos.push(self.restaking_config.clone()); + account_infos.push(self.ncn.clone()); + account_infos.push(self.operator.clone()); + account_infos.push(self.ncn_operator_state.clone()); + account_infos.push(self.epoch_snapshot.clone()); + account_infos.push(self.operator_snapshot.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `InitializeOperatorSnapshot` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` ncn_config +/// 1. `[]` restaking_config +/// 2. `[]` ncn +/// 3. `[]` operator +/// 4. `[]` ncn_operator_state +/// 5. `[writable]` epoch_snapshot +/// 6. `[writable]` operator_snapshot +/// 7. `[writable, signer]` payer +/// 8. `[]` restaking_program_id +/// 9. `[]` system_program +#[derive(Clone, Debug)] +pub struct InitializeOperatorSnapshotCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> InitializeOperatorSnapshotCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(InitializeOperatorSnapshotCpiBuilderInstruction { + __program: program, + ncn_config: None, + restaking_config: None, + ncn: None, + operator: None, + ncn_operator_state: None, + epoch_snapshot: None, + operator_snapshot: None, + payer: None, + restaking_program_id: None, + system_program: None, + first_slot_of_ncn_epoch: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn ncn_config( + &mut self, + ncn_config: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.ncn_config = Some(ncn_config); + self + } + #[inline(always)] + pub fn restaking_config( + &mut self, + restaking_config: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.restaking_config = Some(restaking_config); + self + } + #[inline(always)] + pub fn ncn(&mut self, ncn: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.ncn = Some(ncn); + self + } + #[inline(always)] + pub fn operator( + &mut self, + operator: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.operator = Some(operator); + self + } + #[inline(always)] + pub fn ncn_operator_state( + &mut self, + ncn_operator_state: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.ncn_operator_state = Some(ncn_operator_state); + self + } + #[inline(always)] + pub fn epoch_snapshot( + &mut self, + epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.epoch_snapshot = Some(epoch_snapshot); + self + } + #[inline(always)] + pub fn operator_snapshot( + &mut self, + operator_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.operator_snapshot = Some(operator_snapshot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn restaking_program_id( + &mut self, + restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.restaking_program_id = Some(restaking_program_id); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn first_slot_of_ncn_epoch(&mut self, first_slot_of_ncn_epoch: u64) -> &mut Self { + self.instruction.first_slot_of_ncn_epoch = Some(first_slot_of_ncn_epoch); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = InitializeOperatorSnapshotInstructionArgs { + first_slot_of_ncn_epoch: self.instruction.first_slot_of_ncn_epoch.clone(), + }; + let instruction = InitializeOperatorSnapshotCpi { + __program: self.instruction.__program, + + ncn_config: self.instruction.ncn_config.expect("ncn_config is not set"), + + restaking_config: self + .instruction + .restaking_config + .expect("restaking_config is not set"), + + ncn: self.instruction.ncn.expect("ncn is not set"), + + operator: self.instruction.operator.expect("operator is not set"), + + ncn_operator_state: self + .instruction + .ncn_operator_state + .expect("ncn_operator_state is not set"), + + epoch_snapshot: self + .instruction + .epoch_snapshot + .expect("epoch_snapshot is not set"), + + operator_snapshot: self + .instruction + .operator_snapshot + .expect("operator_snapshot is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + restaking_program_id: self + .instruction + .restaking_program_id + .expect("restaking_program_id is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct InitializeOperatorSnapshotCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + ncn_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ncn: Option<&'b solana_program::account_info::AccountInfo<'a>>, + operator: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ncn_operator_state: Option<&'b solana_program::account_info::AccountInfo<'a>>, + epoch_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + operator_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + first_slot_of_ncn_epoch: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs new file mode 100644 index 0000000..2652400 --- /dev/null +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs @@ -0,0 +1,899 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! + +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct InitializeVaultOperatorDelegationSnapshot { + pub ncn_config: solana_program::pubkey::Pubkey, + + pub restaking_config: solana_program::pubkey::Pubkey, + + pub ncn: solana_program::pubkey::Pubkey, + + pub operator: solana_program::pubkey::Pubkey, + + pub vault: solana_program::pubkey::Pubkey, + + pub vault_ncn_ticket: solana_program::pubkey::Pubkey, + + pub ncn_vault_ticket: solana_program::pubkey::Pubkey, + + pub vault_operator_delegation: solana_program::pubkey::Pubkey, + + pub weight_table: solana_program::pubkey::Pubkey, + + pub epoch_snapshot: solana_program::pubkey::Pubkey, + + pub operator_snapshot: solana_program::pubkey::Pubkey, + + pub vault_operator_delegation_snapshot: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub restaking_program_id: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl InitializeVaultOperatorDelegationSnapshot { + pub fn instruction( + &self, + args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.ncn_config, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.restaking_config, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.ncn, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.operator, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.vault, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.vault_ncn_ticket, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.ncn_vault_ticket, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.vault_operator_delegation, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.weight_table, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.epoch_snapshot, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.operator_snapshot, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.vault_operator_delegation_snapshot, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.restaking_program_id, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = InitializeVaultOperatorDelegationSnapshotInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::JITO_TIP_ROUTER_ID, + accounts, + data, + } + } +} + +#[derive(BorshDeserialize, BorshSerialize)] +pub struct InitializeVaultOperatorDelegationSnapshotInstructionData { + discriminator: u8, +} + +impl InitializeVaultOperatorDelegationSnapshotInstructionData { + pub fn new() -> Self { + Self { discriminator: 7 } + } +} + +impl Default for InitializeVaultOperatorDelegationSnapshotInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct InitializeVaultOperatorDelegationSnapshotInstructionArgs { + pub first_slot_of_ncn_epoch: Option, +} + +/// Instruction builder for `InitializeVaultOperatorDelegationSnapshot`. +/// +/// ### Accounts: +/// +/// 0. `[]` ncn_config +/// 1. `[]` restaking_config +/// 2. `[]` ncn +/// 3. `[]` operator +/// 4. `[]` vault +/// 5. `[]` vault_ncn_ticket +/// 6. `[]` ncn_vault_ticket +/// 7. `[]` vault_operator_delegation +/// 8. `[]` weight_table +/// 9. `[writable]` epoch_snapshot +/// 10. `[writable]` operator_snapshot +/// 11. `[writable]` vault_operator_delegation_snapshot +/// 12. `[writable, signer]` payer +/// 13. `[]` restaking_program_id +/// 14. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct InitializeVaultOperatorDelegationSnapshotBuilder { + ncn_config: Option, + restaking_config: Option, + ncn: Option, + operator: Option, + vault: Option, + vault_ncn_ticket: Option, + ncn_vault_ticket: Option, + vault_operator_delegation: Option, + weight_table: Option, + epoch_snapshot: Option, + operator_snapshot: Option, + vault_operator_delegation_snapshot: Option, + payer: Option, + restaking_program_id: Option, + system_program: Option, + first_slot_of_ncn_epoch: Option, + __remaining_accounts: Vec, +} + +impl InitializeVaultOperatorDelegationSnapshotBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn ncn_config(&mut self, ncn_config: solana_program::pubkey::Pubkey) -> &mut Self { + self.ncn_config = Some(ncn_config); + self + } + #[inline(always)] + pub fn restaking_config( + &mut self, + restaking_config: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.restaking_config = Some(restaking_config); + self + } + #[inline(always)] + pub fn ncn(&mut self, ncn: solana_program::pubkey::Pubkey) -> &mut Self { + self.ncn = Some(ncn); + self + } + #[inline(always)] + pub fn operator(&mut self, operator: solana_program::pubkey::Pubkey) -> &mut Self { + self.operator = Some(operator); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: solana_program::pubkey::Pubkey) -> &mut Self { + self.vault = Some(vault); + self + } + #[inline(always)] + pub fn vault_ncn_ticket( + &mut self, + vault_ncn_ticket: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.vault_ncn_ticket = Some(vault_ncn_ticket); + self + } + #[inline(always)] + pub fn ncn_vault_ticket( + &mut self, + ncn_vault_ticket: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.ncn_vault_ticket = Some(ncn_vault_ticket); + self + } + #[inline(always)] + pub fn vault_operator_delegation( + &mut self, + vault_operator_delegation: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.vault_operator_delegation = Some(vault_operator_delegation); + self + } + #[inline(always)] + pub fn weight_table(&mut self, weight_table: solana_program::pubkey::Pubkey) -> &mut Self { + self.weight_table = Some(weight_table); + self + } + #[inline(always)] + pub fn epoch_snapshot(&mut self, epoch_snapshot: solana_program::pubkey::Pubkey) -> &mut Self { + self.epoch_snapshot = Some(epoch_snapshot); + self + } + #[inline(always)] + pub fn operator_snapshot( + &mut self, + operator_snapshot: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.operator_snapshot = Some(operator_snapshot); + self + } + #[inline(always)] + pub fn vault_operator_delegation_snapshot( + &mut self, + vault_operator_delegation_snapshot: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.vault_operator_delegation_snapshot = Some(vault_operator_delegation_snapshot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + #[inline(always)] + pub fn restaking_program_id( + &mut self, + restaking_program_id: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.restaking_program_id = Some(restaking_program_id); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn first_slot_of_ncn_epoch(&mut self, first_slot_of_ncn_epoch: u64) -> &mut Self { + self.first_slot_of_ncn_epoch = Some(first_slot_of_ncn_epoch); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = InitializeVaultOperatorDelegationSnapshot { + ncn_config: self.ncn_config.expect("ncn_config is not set"), + restaking_config: self.restaking_config.expect("restaking_config is not set"), + ncn: self.ncn.expect("ncn is not set"), + operator: self.operator.expect("operator is not set"), + vault: self.vault.expect("vault is not set"), + vault_ncn_ticket: self.vault_ncn_ticket.expect("vault_ncn_ticket is not set"), + ncn_vault_ticket: self.ncn_vault_ticket.expect("ncn_vault_ticket is not set"), + vault_operator_delegation: self + .vault_operator_delegation + .expect("vault_operator_delegation is not set"), + weight_table: self.weight_table.expect("weight_table is not set"), + epoch_snapshot: self.epoch_snapshot.expect("epoch_snapshot is not set"), + operator_snapshot: self + .operator_snapshot + .expect("operator_snapshot is not set"), + vault_operator_delegation_snapshot: self + .vault_operator_delegation_snapshot + .expect("vault_operator_delegation_snapshot is not set"), + payer: self.payer.expect("payer is not set"), + restaking_program_id: self + .restaking_program_id + .expect("restaking_program_id is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = InitializeVaultOperatorDelegationSnapshotInstructionArgs { + first_slot_of_ncn_epoch: self.first_slot_of_ncn_epoch.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `initialize_vault_operator_delegation_snapshot` CPI accounts. +pub struct InitializeVaultOperatorDelegationSnapshotCpiAccounts<'a, 'b> { + pub ncn_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn: &'b solana_program::account_info::AccountInfo<'a>, + + pub operator: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault_ncn_ticket: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn_vault_ticket: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault_operator_delegation: &'b solana_program::account_info::AccountInfo<'a>, + + pub weight_table: &'b solana_program::account_info::AccountInfo<'a>, + + pub epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub operator_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault_operator_delegation_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `initialize_vault_operator_delegation_snapshot` CPI instruction. +pub struct InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_config: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn: &'b solana_program::account_info::AccountInfo<'a>, + + pub operator: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault_ncn_ticket: &'b solana_program::account_info::AccountInfo<'a>, + + pub ncn_vault_ticket: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault_operator_delegation: &'b solana_program::account_info::AccountInfo<'a>, + + pub weight_table: &'b solana_program::account_info::AccountInfo<'a>, + + pub epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub operator_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault_operator_delegation_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, +} + +impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: InitializeVaultOperatorDelegationSnapshotCpiAccounts<'a, 'b>, + args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, + ) -> Self { + Self { + __program: program, + ncn_config: accounts.ncn_config, + restaking_config: accounts.restaking_config, + ncn: accounts.ncn, + operator: accounts.operator, + vault: accounts.vault, + vault_ncn_ticket: accounts.vault_ncn_ticket, + ncn_vault_ticket: accounts.ncn_vault_ticket, + vault_operator_delegation: accounts.vault_operator_delegation, + weight_table: accounts.weight_table, + epoch_snapshot: accounts.epoch_snapshot, + operator_snapshot: accounts.operator_snapshot, + vault_operator_delegation_snapshot: accounts.vault_operator_delegation_snapshot, + payer: accounts.payer, + restaking_program_id: accounts.restaking_program_id, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.ncn_config.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.restaking_config.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.ncn.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.operator.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.vault.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.vault_ncn_ticket.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.ncn_vault_ticket.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.vault_operator_delegation.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.weight_table.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.epoch_snapshot.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.operator_snapshot.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.vault_operator_delegation_snapshot.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.restaking_program_id.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = InitializeVaultOperatorDelegationSnapshotInstructionData::new() + .try_to_vec() + .unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::JITO_TIP_ROUTER_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(15 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.ncn_config.clone()); + account_infos.push(self.restaking_config.clone()); + account_infos.push(self.ncn.clone()); + account_infos.push(self.operator.clone()); + account_infos.push(self.vault.clone()); + account_infos.push(self.vault_ncn_ticket.clone()); + account_infos.push(self.ncn_vault_ticket.clone()); + account_infos.push(self.vault_operator_delegation.clone()); + account_infos.push(self.weight_table.clone()); + account_infos.push(self.epoch_snapshot.clone()); + account_infos.push(self.operator_snapshot.clone()); + account_infos.push(self.vault_operator_delegation_snapshot.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `InitializeVaultOperatorDelegationSnapshot` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` ncn_config +/// 1. `[]` restaking_config +/// 2. `[]` ncn +/// 3. `[]` operator +/// 4. `[]` vault +/// 5. `[]` vault_ncn_ticket +/// 6. `[]` ncn_vault_ticket +/// 7. `[]` vault_operator_delegation +/// 8. `[]` weight_table +/// 9. `[writable]` epoch_snapshot +/// 10. `[writable]` operator_snapshot +/// 11. `[writable]` vault_operator_delegation_snapshot +/// 12. `[writable, signer]` payer +/// 13. `[]` restaking_program_id +/// 14. `[]` system_program +#[derive(Clone, Debug)] +pub struct InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new( + InitializeVaultOperatorDelegationSnapshotCpiBuilderInstruction { + __program: program, + ncn_config: None, + restaking_config: None, + ncn: None, + operator: None, + vault: None, + vault_ncn_ticket: None, + ncn_vault_ticket: None, + vault_operator_delegation: None, + weight_table: None, + epoch_snapshot: None, + operator_snapshot: None, + vault_operator_delegation_snapshot: None, + payer: None, + restaking_program_id: None, + system_program: None, + first_slot_of_ncn_epoch: None, + __remaining_accounts: Vec::new(), + }, + ); + Self { instruction } + } + #[inline(always)] + pub fn ncn_config( + &mut self, + ncn_config: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.ncn_config = Some(ncn_config); + self + } + #[inline(always)] + pub fn restaking_config( + &mut self, + restaking_config: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.restaking_config = Some(restaking_config); + self + } + #[inline(always)] + pub fn ncn(&mut self, ncn: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.ncn = Some(ncn); + self + } + #[inline(always)] + pub fn operator( + &mut self, + operator: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.operator = Some(operator); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.vault = Some(vault); + self + } + #[inline(always)] + pub fn vault_ncn_ticket( + &mut self, + vault_ncn_ticket: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.vault_ncn_ticket = Some(vault_ncn_ticket); + self + } + #[inline(always)] + pub fn ncn_vault_ticket( + &mut self, + ncn_vault_ticket: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.ncn_vault_ticket = Some(ncn_vault_ticket); + self + } + #[inline(always)] + pub fn vault_operator_delegation( + &mut self, + vault_operator_delegation: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.vault_operator_delegation = Some(vault_operator_delegation); + self + } + #[inline(always)] + pub fn weight_table( + &mut self, + weight_table: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.weight_table = Some(weight_table); + self + } + #[inline(always)] + pub fn epoch_snapshot( + &mut self, + epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.epoch_snapshot = Some(epoch_snapshot); + self + } + #[inline(always)] + pub fn operator_snapshot( + &mut self, + operator_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.operator_snapshot = Some(operator_snapshot); + self + } + #[inline(always)] + pub fn vault_operator_delegation_snapshot( + &mut self, + vault_operator_delegation_snapshot: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.vault_operator_delegation_snapshot = + Some(vault_operator_delegation_snapshot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn restaking_program_id( + &mut self, + restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.restaking_program_id = Some(restaking_program_id); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn first_slot_of_ncn_epoch(&mut self, first_slot_of_ncn_epoch: u64) -> &mut Self { + self.instruction.first_slot_of_ncn_epoch = Some(first_slot_of_ncn_epoch); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = InitializeVaultOperatorDelegationSnapshotInstructionArgs { + first_slot_of_ncn_epoch: self.instruction.first_slot_of_ncn_epoch.clone(), + }; + let instruction = InitializeVaultOperatorDelegationSnapshotCpi { + __program: self.instruction.__program, + + ncn_config: self.instruction.ncn_config.expect("ncn_config is not set"), + + restaking_config: self + .instruction + .restaking_config + .expect("restaking_config is not set"), + + ncn: self.instruction.ncn.expect("ncn is not set"), + + operator: self.instruction.operator.expect("operator is not set"), + + vault: self.instruction.vault.expect("vault is not set"), + + vault_ncn_ticket: self + .instruction + .vault_ncn_ticket + .expect("vault_ncn_ticket is not set"), + + ncn_vault_ticket: self + .instruction + .ncn_vault_ticket + .expect("ncn_vault_ticket is not set"), + + vault_operator_delegation: self + .instruction + .vault_operator_delegation + .expect("vault_operator_delegation is not set"), + + weight_table: self + .instruction + .weight_table + .expect("weight_table is not set"), + + epoch_snapshot: self + .instruction + .epoch_snapshot + .expect("epoch_snapshot is not set"), + + operator_snapshot: self + .instruction + .operator_snapshot + .expect("operator_snapshot is not set"), + + vault_operator_delegation_snapshot: self + .instruction + .vault_operator_delegation_snapshot + .expect("vault_operator_delegation_snapshot is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + restaking_program_id: self + .instruction + .restaking_program_id + .expect("restaking_program_id is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct InitializeVaultOperatorDelegationSnapshotCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + ncn_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ncn: Option<&'b solana_program::account_info::AccountInfo<'a>>, + operator: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault_ncn_ticket: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ncn_vault_ticket: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault_operator_delegation: Option<&'b solana_program::account_info::AccountInfo<'a>>, + weight_table: Option<&'b solana_program::account_info::AccountInfo<'a>>, + epoch_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + operator_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault_operator_delegation_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + first_slot_of_ncn_epoch: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/jito_tip_router/src/generated/instructions/mod.rs b/clients/rust/jito_tip_router/src/generated/instructions/mod.rs index 076a221..9446715 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/mod.rs @@ -7,11 +7,14 @@ pub(crate) mod r#admin_update_weight_table; pub(crate) mod r#initialize_epoch_snapshot; pub(crate) mod r#initialize_n_c_n_config; +pub(crate) mod r#initialize_operator_snapshot; +pub(crate) mod r#initialize_vault_operator_delegation_snapshot; pub(crate) mod r#initialize_weight_table; pub(crate) mod r#set_config_fees; pub(crate) mod r#set_new_admin; pub use self::{ r#admin_update_weight_table::*, r#initialize_epoch_snapshot::*, r#initialize_n_c_n_config::*, + r#initialize_operator_snapshot::*, r#initialize_vault_operator_delegation_snapshot::*, r#initialize_weight_table::*, r#set_config_fees::*, r#set_new_admin::*, }; diff --git a/clients/rust/jito_tip_router/src/generated/types/mod.rs b/clients/rust/jito_tip_router/src/generated/types/mod.rs index 1940263..ea35df8 100644 --- a/clients/rust/jito_tip_router/src/generated/types/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/types/mod.rs @@ -7,10 +7,6 @@ pub(crate) mod r#config_admin_role; pub(crate) mod r#fee; pub(crate) mod r#fees; -pub(crate) mod r#vault_operator_delegation_snapshot; pub(crate) mod r#weight_entry; -pub use self::{ - r#config_admin_role::*, r#fee::*, r#fees::*, r#vault_operator_delegation_snapshot::*, - r#weight_entry::*, -}; +pub use self::{r#config_admin_role::*, r#fee::*, r#fees::*, r#weight_entry::*}; diff --git a/clients/rust/jito_tip_router/src/generated/types/vault_operator_delegation_snapshot.rs b/clients/rust/jito_tip_router/src/generated/types/vault_operator_delegation_snapshot.rs deleted file mode 100644 index 1b4099d..0000000 --- a/clients/rust/jito_tip_router/src/generated/types/vault_operator_delegation_snapshot.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! This code was AUTOGENERATED using the kinobi library. -//! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun kinobi to update it. -//! -//! - -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::pubkey::Pubkey; - -#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct VaultOperatorDelegationSnapshot { - #[cfg_attr( - feature = "serde", - serde(with = "serde_with::As::") - )] - pub vault: Pubkey, - #[cfg_attr( - feature = "serde", - serde(with = "serde_with::As::") - )] - pub st_mint: Pubkey, - pub total_security: u64, - pub total_votes: u128, - pub slot_set: u64, - #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] - pub reserved: [u8; 128], -} diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index 5a7122e..d5d934f 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -155,7 +155,7 @@ impl EpochSnapshot { votes: u128, ) -> Result<(), TipRouterError> { if self.finalized() { - return Err(TipRouterError::OperatorFinalized.into()); + return Err(TipRouterError::OperatorFinalized); } self.operators_registered = PodU64::from( @@ -214,6 +214,7 @@ impl Discriminator for OperatorSnapshot { } impl OperatorSnapshot { + #[allow(clippy::too_many_arguments)] pub fn new( operator: Pubkey, ncn: Pubkey, @@ -361,7 +362,7 @@ impl OperatorSnapshot { votes: u128, ) -> Result<(), TipRouterError> { if self.finalized() { - return Err(TipRouterError::VaultOperatorDelegationFinalized.into()); + return Err(TipRouterError::VaultOperatorDelegationFinalized); } self.vault_operator_delegations_registered = PodU64::from( @@ -416,6 +417,7 @@ impl Discriminator for VaultOperatorDelegationSnapshot { } impl VaultOperatorDelegationSnapshot { + #[allow(clippy::too_many_arguments)] pub fn new( vault: Pubkey, operator: Pubkey, @@ -442,7 +444,7 @@ impl VaultOperatorDelegationSnapshot { reserved: [0; 128], } } - + #[allow(clippy::too_many_arguments)] pub fn new_active( vault: Pubkey, operator: Pubkey, @@ -491,6 +493,7 @@ impl VaultOperatorDelegationSnapshot { ) } + #[allow(clippy::too_many_arguments)] pub fn create_snapshot( vault: Pubkey, operator: Pubkey, diff --git a/idl/jito_tip_router.json b/idl/jito_tip_router.json index b7d32e8..62150a7 100644 --- a/idl/jito_tip_router.json +++ b/idl/jito_tip_router.json @@ -319,6 +319,165 @@ "type": "u8", "value": 5 } + }, + { + "name": "InitializeOperatorSnapshot", + "accounts": [ + { + "name": "ncnConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "restakingConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "ncn", + "isMut": false, + "isSigner": false + }, + { + "name": "operator", + "isMut": false, + "isSigner": false + }, + { + "name": "ncnOperatorState", + "isMut": false, + "isSigner": false + }, + { + "name": "epochSnapshot", + "isMut": true, + "isSigner": false + }, + { + "name": "operatorSnapshot", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "restakingProgramId", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "firstSlotOfNcnEpoch", + "type": { + "option": "u64" + } + } + ], + "discriminant": { + "type": "u8", + "value": 6 + } + }, + { + "name": "InitializeVaultOperatorDelegationSnapshot", + "accounts": [ + { + "name": "ncnConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "restakingConfig", + "isMut": false, + "isSigner": false + }, + { + "name": "ncn", + "isMut": false, + "isSigner": false + }, + { + "name": "operator", + "isMut": false, + "isSigner": false + }, + { + "name": "vault", + "isMut": false, + "isSigner": false + }, + { + "name": "vaultNcnTicket", + "isMut": false, + "isSigner": false + }, + { + "name": "ncnVaultTicket", + "isMut": false, + "isSigner": false + }, + { + "name": "vaultOperatorDelegation", + "isMut": false, + "isSigner": false + }, + { + "name": "weightTable", + "isMut": false, + "isSigner": false + }, + { + "name": "epochSnapshot", + "isMut": true, + "isSigner": false + }, + { + "name": "operatorSnapshot", + "isMut": true, + "isSigner": false + }, + { + "name": "vaultOperatorDelegationSnapshot", + "isMut": true, + "isSigner": false + }, + { + "name": "payer", + "isMut": true, + "isSigner": true + }, + { + "name": "restakingProgramId", + "isMut": false, + "isSigner": false + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false + } + ], + "args": [ + { + "name": "firstSlotOfNcnEpoch", + "type": { + "option": "u64" + } + } + ], + "discriminant": { + "type": "u8", + "value": 7 + } } ], "accounts": [ @@ -337,6 +496,10 @@ "defined": "PodU64" } }, + { + "name": "bump", + "type": "u8" + }, { "name": "slotCreated", "type": { @@ -344,8 +507,10 @@ } }, { - "name": "bump", - "type": "u8" + "name": "slotFinalized", + "type": { + "defined": "PodU64" + } }, { "name": "ncnFees", @@ -365,6 +530,12 @@ "defined": "PodU64" } }, + { + "name": "validOperatorVaultDelegations", + "type": { + "defined": "PodU64" + } + }, { "name": "totalVotes", "type": { @@ -402,6 +573,10 @@ "defined": "PodU64" } }, + { + "name": "bump", + "type": "u8" + }, { "name": "slotCreated", "type": { @@ -409,8 +584,16 @@ } }, { - "name": "bump", - "type": "u8" + "name": "slotFinalized", + "type": { + "defined": "PodU64" + } + }, + { + "name": "isActive", + "type": { + "defined": "PodBool" + } }, { "name": "operatorFeeBps", @@ -418,6 +601,24 @@ "defined": "PodU16" } }, + { + "name": "vaultOperatorDelegationCount", + "type": { + "defined": "PodU64" + } + }, + { + "name": "vaultOperatorDelegationsRegistered", + "type": { + "defined": "PodU64" + } + }, + { + "name": "validOperatorVaultDelegations", + "type": { + "defined": "PodU64" + } + }, { "name": "totalVotes", "type": { @@ -425,32 +626,70 @@ } }, { - "name": "numVaultOperatorDelegations", + "name": "reserved", "type": { - "defined": "PodU16" + "array": [ + "u8", + 128 + ] } + } + ] + } + }, + { + "name": "VaultOperatorDelegationSnapshot", + "type": { + "kind": "struct", + "fields": [ + { + "name": "vault", + "type": "publicKey" }, { - "name": "vaultOperatorDelegationsRegistered", + "name": "operator", + "type": "publicKey" + }, + { + "name": "ncn", + "type": "publicKey" + }, + { + "name": "ncnEpoch", "type": { - "defined": "PodU16" + "defined": "PodU64" } }, { - "name": "slotSet", + "name": "bump", + "type": "u8" + }, + { + "name": "slotCreated", "type": { "defined": "PodU64" } }, { - "name": "vaultOperatorDelegations", + "name": "isActive", "type": { - "array": [ - { - "defined": "VaultOperatorDelegationSnapshot" - }, - 32 - ] + "defined": "PodBool" + } + }, + { + "name": "stMint", + "type": "publicKey" + }, + { + "name": "totalSecurity", + "type": { + "defined": "PodU64" + } + }, + { + "name": "totalVotes", + "type": { + "defined": "PodU128" } }, { @@ -554,49 +793,6 @@ } ], "types": [ - { - "name": "VaultOperatorDelegationSnapshot", - "type": { - "kind": "struct", - "fields": [ - { - "name": "vault", - "type": "publicKey" - }, - { - "name": "stMint", - "type": "publicKey" - }, - { - "name": "totalSecurity", - "type": { - "defined": "PodU64" - } - }, - { - "name": "totalVotes", - "type": { - "defined": "PodU128" - } - }, - { - "name": "slotSet", - "type": { - "defined": "PodU64" - } - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 128 - ] - } - } - ] - } - }, { "name": "Fees", "type": { @@ -807,6 +1003,21 @@ "code": 8718, "name": "WeightNotFound", "msg": "Weight not found" + }, + { + "code": 8719, + "name": "NoOperators", + "msg": "No operators in ncn" + }, + { + "code": 8720, + "name": "VaultOperatorDelegationFinalized", + "msg": "Vault operator delegation is already finalized - should not happen" + }, + { + "code": 8721, + "name": "OperatorFinalized", + "msg": "Operator is already finalized - should not happen" } ], "metadata": { diff --git a/scripts/generate-clients.js b/scripts/generate-clients.js index 73a0d1e..3119c70 100644 --- a/scripts/generate-clients.js +++ b/scripts/generate-clients.js @@ -81,6 +81,22 @@ weightTableKinobi.update(kinobi.bottomUpTransformerVisitor([ }; }, }, + { + // PodBool -> bool + select: (node) => { + return ( + kinobi.isNode(node, "structFieldTypeNode") && + node.type.name === "podBool" + ); + }, + transform: (node) => { + kinobi.assertIsNode(node, "structFieldTypeNode"); + return { + ...node, + type: kinobi.numberTypeNode("bool"), + }; + }, + }, // add 8 byte discriminator to accountNode { select: (node) => { From 200fca4502efabd9540e0c1938f2ed21db6b8780 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Tue, 12 Nov 2024 09:36:06 -0800 Subject: [PATCH 08/28] tip router client up to date --- Cargo.lock | 1 + .../instructions/adminUpdateWeightTable.ts | 30 +-- .../instructions/initializeEpochSnapshot.ts | 30 +-- .../instructions/initializeNCNConfig.ts | 30 +-- .../initializeOperatorSnapshot.ts | 30 +-- ...itializeVaultOperatorDelegationSnapshot.ts | 48 +++-- .../instructions/initializeWeightTable.ts | 30 +-- .../instructions/setConfigFees.ts | 30 +-- .../instructions/setNewAdmin.ts | 30 +-- .../instructions/admin_update_weight_table.rs | 48 ++--- .../instructions/initialize_epoch_snapshot.rs | 48 ++--- .../instructions/initialize_n_c_n_config.rs | 48 ++--- .../initialize_operator_snapshot.rs | 48 ++--- ...lize_vault_operator_delegation_snapshot.rs | 98 ++++++--- .../instructions/initialize_weight_table.rs | 48 ++--- .../generated/instructions/set_config_fees.rs | 48 ++--- .../generated/instructions/set_new_admin.rs | 48 ++--- core/src/instruction.rs | 19 +- idl/jito_tip_router.json | 21 +- .../tests/fixtures/tip_router_client.rs | 188 ++++++++++++++++-- program/Cargo.toml | 1 + program/src/admin_update_weight_table.rs | 6 +- program/src/initialize_epoch_snapshot.rs | 8 +- program/src/initialize_ncn_config.rs | 6 +- program/src/initialize_operator_snapshot.rs | 12 +- ...lize_vault_operator_delegation_snapshot.rs | 39 ++-- program/src/initialize_weight_table.rs | 8 +- program/src/set_config_fees.rs | 6 +- program/src/set_new_admin.rs | 4 +- 29 files changed, 614 insertions(+), 397 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44894c2..210961a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2553,6 +2553,7 @@ dependencies = [ "jito-restaking-sdk", "jito-tip-router-core", "jito-vault-core", + "jito-vault-program", "jito-vault-sdk", "shank", "solana-program 1.18.26", diff --git a/clients/js/jito_tip_router/instructions/adminUpdateWeightTable.ts b/clients/js/jito_tip_router/instructions/adminUpdateWeightTable.ts index 36e207f..033d67a 100644 --- a/clients/js/jito_tip_router/instructions/adminUpdateWeightTable.ts +++ b/clients/js/jito_tip_router/instructions/adminUpdateWeightTable.ts @@ -46,7 +46,7 @@ export type AdminUpdateWeightTableInstruction< TAccountWeightTable extends string | IAccountMeta = string, TAccountWeightTableAdmin extends string | IAccountMeta = string, TAccountMint extends string | IAccountMeta = string, - TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountRestakingProgram extends string | IAccountMeta = string, TRemainingAccounts extends readonly IAccountMeta[] = [], > = IInstruction & IInstructionWithData & @@ -63,9 +63,9 @@ export type AdminUpdateWeightTableInstruction< TAccountMint extends string ? ReadonlyAccount : TAccountMint, - TAccountRestakingProgramId extends string - ? ReadonlyAccount - : TAccountRestakingProgramId, + TAccountRestakingProgram extends string + ? ReadonlyAccount + : TAccountRestakingProgram, ...TRemainingAccounts, ] >; @@ -118,13 +118,13 @@ export type AdminUpdateWeightTableInput< TAccountWeightTable extends string = string, TAccountWeightTableAdmin extends string = string, TAccountMint extends string = string, - TAccountRestakingProgramId extends string = string, + TAccountRestakingProgram extends string = string, > = { ncn: Address; weightTable: Address; weightTableAdmin: TransactionSigner; mint: Address; - restakingProgramId: Address; + restakingProgram: Address; ncnEpoch: AdminUpdateWeightTableInstructionDataArgs['ncnEpoch']; weight: AdminUpdateWeightTableInstructionDataArgs['weight']; }; @@ -134,7 +134,7 @@ export function getAdminUpdateWeightTableInstruction< TAccountWeightTable extends string, TAccountWeightTableAdmin extends string, TAccountMint extends string, - TAccountRestakingProgramId extends string, + TAccountRestakingProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( input: AdminUpdateWeightTableInput< @@ -142,7 +142,7 @@ export function getAdminUpdateWeightTableInstruction< TAccountWeightTable, TAccountWeightTableAdmin, TAccountMint, - TAccountRestakingProgramId + TAccountRestakingProgram >, config?: { programAddress?: TProgramAddress } ): AdminUpdateWeightTableInstruction< @@ -151,7 +151,7 @@ export function getAdminUpdateWeightTableInstruction< TAccountWeightTable, TAccountWeightTableAdmin, TAccountMint, - TAccountRestakingProgramId + TAccountRestakingProgram > { // Program address. const programAddress = @@ -166,8 +166,8 @@ export function getAdminUpdateWeightTableInstruction< isWritable: false, }, mint: { value: input.mint ?? null, isWritable: false }, - restakingProgramId: { - value: input.restakingProgramId ?? null, + restakingProgram: { + value: input.restakingProgram ?? null, isWritable: false, }, }; @@ -186,7 +186,7 @@ export function getAdminUpdateWeightTableInstruction< getAccountMeta(accounts.weightTable), getAccountMeta(accounts.weightTableAdmin), getAccountMeta(accounts.mint), - getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.restakingProgram), ], programAddress, data: getAdminUpdateWeightTableInstructionDataEncoder().encode( @@ -198,7 +198,7 @@ export function getAdminUpdateWeightTableInstruction< TAccountWeightTable, TAccountWeightTableAdmin, TAccountMint, - TAccountRestakingProgramId + TAccountRestakingProgram >; return instruction; @@ -214,7 +214,7 @@ export type ParsedAdminUpdateWeightTableInstruction< weightTable: TAccountMetas[1]; weightTableAdmin: TAccountMetas[2]; mint: TAccountMetas[3]; - restakingProgramId: TAccountMetas[4]; + restakingProgram: TAccountMetas[4]; }; data: AdminUpdateWeightTableInstructionData; }; @@ -244,7 +244,7 @@ export function parseAdminUpdateWeightTableInstruction< weightTable: getNextAccount(), weightTableAdmin: getNextAccount(), mint: getNextAccount(), - restakingProgramId: getNextAccount(), + restakingProgram: getNextAccount(), }, data: getAdminUpdateWeightTableInstructionDataDecoder().decode( instruction.data diff --git a/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts b/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts index 1e9857d..66cb8f9 100644 --- a/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts +++ b/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts @@ -50,7 +50,7 @@ export type InitializeEpochSnapshotInstruction< TAccountWeightTable extends string | IAccountMeta = string, TAccountEpochSnapshot extends string | IAccountMeta = string, TAccountPayer extends string | IAccountMeta = string, - TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountRestakingProgram extends string | IAccountMeta = string, TAccountSystemProgram extends | string | IAccountMeta = '11111111111111111111111111111111', @@ -76,9 +76,9 @@ export type InitializeEpochSnapshotInstruction< ? WritableSignerAccount & IAccountSignerMeta : TAccountPayer, - TAccountRestakingProgramId extends string - ? ReadonlyAccount - : TAccountRestakingProgramId, + TAccountRestakingProgram extends string + ? ReadonlyAccount + : TAccountRestakingProgram, TAccountSystemProgram extends string ? ReadonlyAccount : TAccountSystemProgram, @@ -132,7 +132,7 @@ export type InitializeEpochSnapshotInput< TAccountWeightTable extends string = string, TAccountEpochSnapshot extends string = string, TAccountPayer extends string = string, - TAccountRestakingProgramId extends string = string, + TAccountRestakingProgram extends string = string, TAccountSystemProgram extends string = string, > = { ncnConfig: Address; @@ -141,7 +141,7 @@ export type InitializeEpochSnapshotInput< weightTable: Address; epochSnapshot: Address; payer: TransactionSigner; - restakingProgramId: Address; + restakingProgram: Address; systemProgram?: Address; firstSlotOfNcnEpoch: InitializeEpochSnapshotInstructionDataArgs['firstSlotOfNcnEpoch']; }; @@ -153,7 +153,7 @@ export function getInitializeEpochSnapshotInstruction< TAccountWeightTable extends string, TAccountEpochSnapshot extends string, TAccountPayer extends string, - TAccountRestakingProgramId extends string, + TAccountRestakingProgram extends string, TAccountSystemProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( @@ -164,7 +164,7 @@ export function getInitializeEpochSnapshotInstruction< TAccountWeightTable, TAccountEpochSnapshot, TAccountPayer, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram >, config?: { programAddress?: TProgramAddress } @@ -176,7 +176,7 @@ export function getInitializeEpochSnapshotInstruction< TAccountWeightTable, TAccountEpochSnapshot, TAccountPayer, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram > { // Program address. @@ -194,8 +194,8 @@ export function getInitializeEpochSnapshotInstruction< weightTable: { value: input.weightTable ?? null, isWritable: false }, epochSnapshot: { value: input.epochSnapshot ?? null, isWritable: true }, payer: { value: input.payer ?? null, isWritable: true }, - restakingProgramId: { - value: input.restakingProgramId ?? null, + restakingProgram: { + value: input.restakingProgram ?? null, isWritable: false, }, systemProgram: { value: input.systemProgram ?? null, isWritable: false }, @@ -223,7 +223,7 @@ export function getInitializeEpochSnapshotInstruction< getAccountMeta(accounts.weightTable), getAccountMeta(accounts.epochSnapshot), getAccountMeta(accounts.payer), - getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.restakingProgram), getAccountMeta(accounts.systemProgram), ], programAddress, @@ -238,7 +238,7 @@ export function getInitializeEpochSnapshotInstruction< TAccountWeightTable, TAccountEpochSnapshot, TAccountPayer, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram >; @@ -257,7 +257,7 @@ export type ParsedInitializeEpochSnapshotInstruction< weightTable: TAccountMetas[3]; epochSnapshot: TAccountMetas[4]; payer: TAccountMetas[5]; - restakingProgramId: TAccountMetas[6]; + restakingProgram: TAccountMetas[6]; systemProgram: TAccountMetas[7]; }; data: InitializeEpochSnapshotInstructionData; @@ -290,7 +290,7 @@ export function parseInitializeEpochSnapshotInstruction< weightTable: getNextAccount(), epochSnapshot: getNextAccount(), payer: getNextAccount(), - restakingProgramId: getNextAccount(), + restakingProgram: getNextAccount(), systemProgram: getNextAccount(), }, data: getInitializeEpochSnapshotInstructionDataDecoder().decode( diff --git a/clients/js/jito_tip_router/instructions/initializeNCNConfig.ts b/clients/js/jito_tip_router/instructions/initializeNCNConfig.ts index 0f7834e..29c966b 100644 --- a/clients/js/jito_tip_router/instructions/initializeNCNConfig.ts +++ b/clients/js/jito_tip_router/instructions/initializeNCNConfig.ts @@ -46,7 +46,7 @@ export type InitializeNCNConfigInstruction< TAccountNcnAdmin extends string | IAccountMeta = string, TAccountFeeWallet extends string | IAccountMeta = string, TAccountTieBreakerAdmin extends string | IAccountMeta = string, - TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountRestakingProgram extends string | IAccountMeta = string, TAccountSystemProgram extends | string | IAccountMeta = '11111111111111111111111111111111', @@ -72,9 +72,9 @@ export type InitializeNCNConfigInstruction< TAccountTieBreakerAdmin extends string ? ReadonlyAccount : TAccountTieBreakerAdmin, - TAccountRestakingProgramId extends string - ? ReadonlyAccount - : TAccountRestakingProgramId, + TAccountRestakingProgram extends string + ? ReadonlyAccount + : TAccountRestakingProgram, TAccountSystemProgram extends string ? ReadonlyAccount : TAccountSystemProgram, @@ -136,7 +136,7 @@ export type InitializeNCNConfigInput< TAccountNcnAdmin extends string = string, TAccountFeeWallet extends string = string, TAccountTieBreakerAdmin extends string = string, - TAccountRestakingProgramId extends string = string, + TAccountRestakingProgram extends string = string, TAccountSystemProgram extends string = string, > = { restakingConfig: Address; @@ -145,7 +145,7 @@ export type InitializeNCNConfigInput< ncnAdmin: TransactionSigner; feeWallet: Address; tieBreakerAdmin: Address; - restakingProgramId: Address; + restakingProgram: Address; systemProgram?: Address; daoFeeBps: InitializeNCNConfigInstructionDataArgs['daoFeeBps']; ncnFeeBps: InitializeNCNConfigInstructionDataArgs['ncnFeeBps']; @@ -159,7 +159,7 @@ export function getInitializeNCNConfigInstruction< TAccountNcnAdmin extends string, TAccountFeeWallet extends string, TAccountTieBreakerAdmin extends string, - TAccountRestakingProgramId extends string, + TAccountRestakingProgram extends string, TAccountSystemProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( @@ -170,7 +170,7 @@ export function getInitializeNCNConfigInstruction< TAccountNcnAdmin, TAccountFeeWallet, TAccountTieBreakerAdmin, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram >, config?: { programAddress?: TProgramAddress } @@ -182,7 +182,7 @@ export function getInitializeNCNConfigInstruction< TAccountNcnAdmin, TAccountFeeWallet, TAccountTieBreakerAdmin, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram > { // Program address. @@ -203,8 +203,8 @@ export function getInitializeNCNConfigInstruction< value: input.tieBreakerAdmin ?? null, isWritable: false, }, - restakingProgramId: { - value: input.restakingProgramId ?? null, + restakingProgram: { + value: input.restakingProgram ?? null, isWritable: false, }, systemProgram: { value: input.systemProgram ?? null, isWritable: false }, @@ -232,7 +232,7 @@ export function getInitializeNCNConfigInstruction< getAccountMeta(accounts.ncnAdmin), getAccountMeta(accounts.feeWallet), getAccountMeta(accounts.tieBreakerAdmin), - getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.restakingProgram), getAccountMeta(accounts.systemProgram), ], programAddress, @@ -247,7 +247,7 @@ export function getInitializeNCNConfigInstruction< TAccountNcnAdmin, TAccountFeeWallet, TAccountTieBreakerAdmin, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram >; @@ -266,7 +266,7 @@ export type ParsedInitializeNCNConfigInstruction< ncnAdmin: TAccountMetas[3]; feeWallet: TAccountMetas[4]; tieBreakerAdmin: TAccountMetas[5]; - restakingProgramId: TAccountMetas[6]; + restakingProgram: TAccountMetas[6]; systemProgram: TAccountMetas[7]; }; data: InitializeNCNConfigInstructionData; @@ -299,7 +299,7 @@ export function parseInitializeNCNConfigInstruction< ncnAdmin: getNextAccount(), feeWallet: getNextAccount(), tieBreakerAdmin: getNextAccount(), - restakingProgramId: getNextAccount(), + restakingProgram: getNextAccount(), systemProgram: getNextAccount(), }, data: getInitializeNCNConfigInstructionDataDecoder().decode( diff --git a/clients/js/jito_tip_router/instructions/initializeOperatorSnapshot.ts b/clients/js/jito_tip_router/instructions/initializeOperatorSnapshot.ts index aa74bff..8e70d5c 100644 --- a/clients/js/jito_tip_router/instructions/initializeOperatorSnapshot.ts +++ b/clients/js/jito_tip_router/instructions/initializeOperatorSnapshot.ts @@ -52,7 +52,7 @@ export type InitializeOperatorSnapshotInstruction< TAccountEpochSnapshot extends string | IAccountMeta = string, TAccountOperatorSnapshot extends string | IAccountMeta = string, TAccountPayer extends string | IAccountMeta = string, - TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountRestakingProgram extends string | IAccountMeta = string, TAccountSystemProgram extends | string | IAccountMeta = '11111111111111111111111111111111', @@ -84,9 +84,9 @@ export type InitializeOperatorSnapshotInstruction< ? WritableSignerAccount & IAccountSignerMeta : TAccountPayer, - TAccountRestakingProgramId extends string - ? ReadonlyAccount - : TAccountRestakingProgramId, + TAccountRestakingProgram extends string + ? ReadonlyAccount + : TAccountRestakingProgram, TAccountSystemProgram extends string ? ReadonlyAccount : TAccountSystemProgram, @@ -142,7 +142,7 @@ export type InitializeOperatorSnapshotInput< TAccountEpochSnapshot extends string = string, TAccountOperatorSnapshot extends string = string, TAccountPayer extends string = string, - TAccountRestakingProgramId extends string = string, + TAccountRestakingProgram extends string = string, TAccountSystemProgram extends string = string, > = { ncnConfig: Address; @@ -153,7 +153,7 @@ export type InitializeOperatorSnapshotInput< epochSnapshot: Address; operatorSnapshot: Address; payer: TransactionSigner; - restakingProgramId: Address; + restakingProgram: Address; systemProgram?: Address; firstSlotOfNcnEpoch: InitializeOperatorSnapshotInstructionDataArgs['firstSlotOfNcnEpoch']; }; @@ -167,7 +167,7 @@ export function getInitializeOperatorSnapshotInstruction< TAccountEpochSnapshot extends string, TAccountOperatorSnapshot extends string, TAccountPayer extends string, - TAccountRestakingProgramId extends string, + TAccountRestakingProgram extends string, TAccountSystemProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( @@ -180,7 +180,7 @@ export function getInitializeOperatorSnapshotInstruction< TAccountEpochSnapshot, TAccountOperatorSnapshot, TAccountPayer, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram >, config?: { programAddress?: TProgramAddress } @@ -194,7 +194,7 @@ export function getInitializeOperatorSnapshotInstruction< TAccountEpochSnapshot, TAccountOperatorSnapshot, TAccountPayer, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram > { // Program address. @@ -220,8 +220,8 @@ export function getInitializeOperatorSnapshotInstruction< isWritable: true, }, payer: { value: input.payer ?? null, isWritable: true }, - restakingProgramId: { - value: input.restakingProgramId ?? null, + restakingProgram: { + value: input.restakingProgram ?? null, isWritable: false, }, systemProgram: { value: input.systemProgram ?? null, isWritable: false }, @@ -251,7 +251,7 @@ export function getInitializeOperatorSnapshotInstruction< getAccountMeta(accounts.epochSnapshot), getAccountMeta(accounts.operatorSnapshot), getAccountMeta(accounts.payer), - getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.restakingProgram), getAccountMeta(accounts.systemProgram), ], programAddress, @@ -268,7 +268,7 @@ export function getInitializeOperatorSnapshotInstruction< TAccountEpochSnapshot, TAccountOperatorSnapshot, TAccountPayer, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram >; @@ -289,7 +289,7 @@ export type ParsedInitializeOperatorSnapshotInstruction< epochSnapshot: TAccountMetas[5]; operatorSnapshot: TAccountMetas[6]; payer: TAccountMetas[7]; - restakingProgramId: TAccountMetas[8]; + restakingProgram: TAccountMetas[8]; systemProgram: TAccountMetas[9]; }; data: InitializeOperatorSnapshotInstructionData; @@ -324,7 +324,7 @@ export function parseInitializeOperatorSnapshotInstruction< epochSnapshot: getNextAccount(), operatorSnapshot: getNextAccount(), payer: getNextAccount(), - restakingProgramId: getNextAccount(), + restakingProgram: getNextAccount(), systemProgram: getNextAccount(), }, data: getInitializeOperatorSnapshotInstructionDataDecoder().decode( diff --git a/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts b/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts index 9416e77..cc6c604 100644 --- a/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts +++ b/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts @@ -63,7 +63,8 @@ export type InitializeVaultOperatorDelegationSnapshotInstruction< | string | IAccountMeta = string, TAccountPayer extends string | IAccountMeta = string, - TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountVaultProgram extends string | IAccountMeta = string, + TAccountRestakingProgram extends string | IAccountMeta = string, TAccountSystemProgram extends | string | IAccountMeta = '11111111111111111111111111111111', @@ -110,9 +111,12 @@ export type InitializeVaultOperatorDelegationSnapshotInstruction< ? WritableSignerAccount & IAccountSignerMeta : TAccountPayer, - TAccountRestakingProgramId extends string - ? ReadonlyAccount - : TAccountRestakingProgramId, + TAccountVaultProgram extends string + ? ReadonlyAccount + : TAccountVaultProgram, + TAccountRestakingProgram extends string + ? ReadonlyAccount + : TAccountRestakingProgram, TAccountSystemProgram extends string ? ReadonlyAccount : TAccountSystemProgram, @@ -174,7 +178,8 @@ export type InitializeVaultOperatorDelegationSnapshotInput< TAccountOperatorSnapshot extends string = string, TAccountVaultOperatorDelegationSnapshot extends string = string, TAccountPayer extends string = string, - TAccountRestakingProgramId extends string = string, + TAccountVaultProgram extends string = string, + TAccountRestakingProgram extends string = string, TAccountSystemProgram extends string = string, > = { ncnConfig: Address; @@ -190,7 +195,8 @@ export type InitializeVaultOperatorDelegationSnapshotInput< operatorSnapshot: Address; vaultOperatorDelegationSnapshot: Address; payer: TransactionSigner; - restakingProgramId: Address; + vaultProgram: Address; + restakingProgram: Address; systemProgram?: Address; firstSlotOfNcnEpoch: InitializeVaultOperatorDelegationSnapshotInstructionDataArgs['firstSlotOfNcnEpoch']; }; @@ -209,7 +215,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountOperatorSnapshot extends string, TAccountVaultOperatorDelegationSnapshot extends string, TAccountPayer extends string, - TAccountRestakingProgramId extends string, + TAccountVaultProgram extends string, + TAccountRestakingProgram extends string, TAccountSystemProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( @@ -227,7 +234,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountOperatorSnapshot, TAccountVaultOperatorDelegationSnapshot, TAccountPayer, - TAccountRestakingProgramId, + TAccountVaultProgram, + TAccountRestakingProgram, TAccountSystemProgram >, config?: { programAddress?: TProgramAddress } @@ -246,7 +254,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountOperatorSnapshot, TAccountVaultOperatorDelegationSnapshot, TAccountPayer, - TAccountRestakingProgramId, + TAccountVaultProgram, + TAccountRestakingProgram, TAccountSystemProgram > { // Program address. @@ -280,8 +289,9 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< isWritable: true, }, payer: { value: input.payer ?? null, isWritable: true }, - restakingProgramId: { - value: input.restakingProgramId ?? null, + vaultProgram: { value: input.vaultProgram ?? null, isWritable: false }, + restakingProgram: { + value: input.restakingProgram ?? null, isWritable: false, }, systemProgram: { value: input.systemProgram ?? null, isWritable: false }, @@ -316,7 +326,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< getAccountMeta(accounts.operatorSnapshot), getAccountMeta(accounts.vaultOperatorDelegationSnapshot), getAccountMeta(accounts.payer), - getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.vaultProgram), + getAccountMeta(accounts.restakingProgram), getAccountMeta(accounts.systemProgram), ], programAddress, @@ -338,7 +349,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountOperatorSnapshot, TAccountVaultOperatorDelegationSnapshot, TAccountPayer, - TAccountRestakingProgramId, + TAccountVaultProgram, + TAccountRestakingProgram, TAccountSystemProgram >; @@ -364,8 +376,9 @@ export type ParsedInitializeVaultOperatorDelegationSnapshotInstruction< operatorSnapshot: TAccountMetas[10]; vaultOperatorDelegationSnapshot: TAccountMetas[11]; payer: TAccountMetas[12]; - restakingProgramId: TAccountMetas[13]; - systemProgram: TAccountMetas[14]; + vaultProgram: TAccountMetas[13]; + restakingProgram: TAccountMetas[14]; + systemProgram: TAccountMetas[15]; }; data: InitializeVaultOperatorDelegationSnapshotInstructionData; }; @@ -381,7 +394,7 @@ export function parseInitializeVaultOperatorDelegationSnapshotInstruction< TProgram, TAccountMetas > { - if (instruction.accounts.length < 15) { + if (instruction.accounts.length < 16) { // TODO: Coded error. throw new Error('Not enough accounts'); } @@ -407,7 +420,8 @@ export function parseInitializeVaultOperatorDelegationSnapshotInstruction< operatorSnapshot: getNextAccount(), vaultOperatorDelegationSnapshot: getNextAccount(), payer: getNextAccount(), - restakingProgramId: getNextAccount(), + vaultProgram: getNextAccount(), + restakingProgram: getNextAccount(), systemProgram: getNextAccount(), }, data: getInitializeVaultOperatorDelegationSnapshotInstructionDataDecoder().decode( diff --git a/clients/js/jito_tip_router/instructions/initializeWeightTable.ts b/clients/js/jito_tip_router/instructions/initializeWeightTable.ts index fb1b904..d6719a1 100644 --- a/clients/js/jito_tip_router/instructions/initializeWeightTable.ts +++ b/clients/js/jito_tip_router/instructions/initializeWeightTable.ts @@ -49,7 +49,7 @@ export type InitializeWeightTableInstruction< TAccountNcn extends string | IAccountMeta = string, TAccountWeightTable extends string | IAccountMeta = string, TAccountPayer extends string | IAccountMeta = string, - TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountRestakingProgram extends string | IAccountMeta = string, TAccountSystemProgram extends | string | IAccountMeta = '11111111111111111111111111111111', @@ -72,9 +72,9 @@ export type InitializeWeightTableInstruction< ? WritableSignerAccount & IAccountSignerMeta : TAccountPayer, - TAccountRestakingProgramId extends string - ? ReadonlyAccount - : TAccountRestakingProgramId, + TAccountRestakingProgram extends string + ? ReadonlyAccount + : TAccountRestakingProgram, TAccountSystemProgram extends string ? ReadonlyAccount : TAccountSystemProgram, @@ -127,7 +127,7 @@ export type InitializeWeightTableInput< TAccountNcn extends string = string, TAccountWeightTable extends string = string, TAccountPayer extends string = string, - TAccountRestakingProgramId extends string = string, + TAccountRestakingProgram extends string = string, TAccountSystemProgram extends string = string, > = { restakingConfig: Address; @@ -135,7 +135,7 @@ export type InitializeWeightTableInput< ncn: Address; weightTable: Address; payer: TransactionSigner; - restakingProgramId: Address; + restakingProgram: Address; systemProgram?: Address; firstSlotOfNcnEpoch: InitializeWeightTableInstructionDataArgs['firstSlotOfNcnEpoch']; }; @@ -146,7 +146,7 @@ export function getInitializeWeightTableInstruction< TAccountNcn extends string, TAccountWeightTable extends string, TAccountPayer extends string, - TAccountRestakingProgramId extends string, + TAccountRestakingProgram extends string, TAccountSystemProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( @@ -156,7 +156,7 @@ export function getInitializeWeightTableInstruction< TAccountNcn, TAccountWeightTable, TAccountPayer, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram >, config?: { programAddress?: TProgramAddress } @@ -167,7 +167,7 @@ export function getInitializeWeightTableInstruction< TAccountNcn, TAccountWeightTable, TAccountPayer, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram > { // Program address. @@ -184,8 +184,8 @@ export function getInitializeWeightTableInstruction< ncn: { value: input.ncn ?? null, isWritable: false }, weightTable: { value: input.weightTable ?? null, isWritable: true }, payer: { value: input.payer ?? null, isWritable: true }, - restakingProgramId: { - value: input.restakingProgramId ?? null, + restakingProgram: { + value: input.restakingProgram ?? null, isWritable: false, }, systemProgram: { value: input.systemProgram ?? null, isWritable: false }, @@ -212,7 +212,7 @@ export function getInitializeWeightTableInstruction< getAccountMeta(accounts.ncn), getAccountMeta(accounts.weightTable), getAccountMeta(accounts.payer), - getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.restakingProgram), getAccountMeta(accounts.systemProgram), ], programAddress, @@ -226,7 +226,7 @@ export function getInitializeWeightTableInstruction< TAccountNcn, TAccountWeightTable, TAccountPayer, - TAccountRestakingProgramId, + TAccountRestakingProgram, TAccountSystemProgram >; @@ -244,7 +244,7 @@ export type ParsedInitializeWeightTableInstruction< ncn: TAccountMetas[2]; weightTable: TAccountMetas[3]; payer: TAccountMetas[4]; - restakingProgramId: TAccountMetas[5]; + restakingProgram: TAccountMetas[5]; systemProgram: TAccountMetas[6]; }; data: InitializeWeightTableInstructionData; @@ -276,7 +276,7 @@ export function parseInitializeWeightTableInstruction< ncn: getNextAccount(), weightTable: getNextAccount(), payer: getNextAccount(), - restakingProgramId: getNextAccount(), + restakingProgram: getNextAccount(), systemProgram: getNextAccount(), }, data: getInitializeWeightTableInstructionDataDecoder().decode( diff --git a/clients/js/jito_tip_router/instructions/setConfigFees.ts b/clients/js/jito_tip_router/instructions/setConfigFees.ts index b6274cd..d5b0dc4 100644 --- a/clients/js/jito_tip_router/instructions/setConfigFees.ts +++ b/clients/js/jito_tip_router/instructions/setConfigFees.ts @@ -50,7 +50,7 @@ export type SetConfigFeesInstruction< TAccountConfig extends string | IAccountMeta = string, TAccountNcn extends string | IAccountMeta = string, TAccountNcnAdmin extends string | IAccountMeta = string, - TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountRestakingProgram extends string | IAccountMeta = string, TRemainingAccounts extends readonly IAccountMeta[] = [], > = IInstruction & IInstructionWithData & @@ -67,9 +67,9 @@ export type SetConfigFeesInstruction< ? ReadonlySignerAccount & IAccountSignerMeta : TAccountNcnAdmin, - TAccountRestakingProgramId extends string - ? ReadonlyAccount - : TAccountRestakingProgramId, + TAccountRestakingProgram extends string + ? ReadonlyAccount + : TAccountRestakingProgram, ...TRemainingAccounts, ] >; @@ -127,13 +127,13 @@ export type SetConfigFeesInput< TAccountConfig extends string = string, TAccountNcn extends string = string, TAccountNcnAdmin extends string = string, - TAccountRestakingProgramId extends string = string, + TAccountRestakingProgram extends string = string, > = { restakingConfig: Address; config: Address; ncn: Address; ncnAdmin: TransactionSigner; - restakingProgramId: Address; + restakingProgram: Address; newDaoFeeBps: SetConfigFeesInstructionDataArgs['newDaoFeeBps']; newNcnFeeBps: SetConfigFeesInstructionDataArgs['newNcnFeeBps']; newBlockEngineFeeBps: SetConfigFeesInstructionDataArgs['newBlockEngineFeeBps']; @@ -145,7 +145,7 @@ export function getSetConfigFeesInstruction< TAccountConfig extends string, TAccountNcn extends string, TAccountNcnAdmin extends string, - TAccountRestakingProgramId extends string, + TAccountRestakingProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( input: SetConfigFeesInput< @@ -153,7 +153,7 @@ export function getSetConfigFeesInstruction< TAccountConfig, TAccountNcn, TAccountNcnAdmin, - TAccountRestakingProgramId + TAccountRestakingProgram >, config?: { programAddress?: TProgramAddress } ): SetConfigFeesInstruction< @@ -162,7 +162,7 @@ export function getSetConfigFeesInstruction< TAccountConfig, TAccountNcn, TAccountNcnAdmin, - TAccountRestakingProgramId + TAccountRestakingProgram > { // Program address. const programAddress = @@ -177,8 +177,8 @@ export function getSetConfigFeesInstruction< config: { value: input.config ?? null, isWritable: true }, ncn: { value: input.ncn ?? null, isWritable: false }, ncnAdmin: { value: input.ncnAdmin ?? null, isWritable: false }, - restakingProgramId: { - value: input.restakingProgramId ?? null, + restakingProgram: { + value: input.restakingProgram ?? null, isWritable: false, }, }; @@ -197,7 +197,7 @@ export function getSetConfigFeesInstruction< getAccountMeta(accounts.config), getAccountMeta(accounts.ncn), getAccountMeta(accounts.ncnAdmin), - getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.restakingProgram), ], programAddress, data: getSetConfigFeesInstructionDataEncoder().encode( @@ -209,7 +209,7 @@ export function getSetConfigFeesInstruction< TAccountConfig, TAccountNcn, TAccountNcnAdmin, - TAccountRestakingProgramId + TAccountRestakingProgram >; return instruction; @@ -225,7 +225,7 @@ export type ParsedSetConfigFeesInstruction< config: TAccountMetas[1]; ncn: TAccountMetas[2]; ncnAdmin: TAccountMetas[3]; - restakingProgramId: TAccountMetas[4]; + restakingProgram: TAccountMetas[4]; }; data: SetConfigFeesInstructionData; }; @@ -255,7 +255,7 @@ export function parseSetConfigFeesInstruction< config: getNextAccount(), ncn: getNextAccount(), ncnAdmin: getNextAccount(), - restakingProgramId: getNextAccount(), + restakingProgram: getNextAccount(), }, data: getSetConfigFeesInstructionDataDecoder().decode(instruction.data), }; diff --git a/clients/js/jito_tip_router/instructions/setNewAdmin.ts b/clients/js/jito_tip_router/instructions/setNewAdmin.ts index eb14e6c..74c02c5 100644 --- a/clients/js/jito_tip_router/instructions/setNewAdmin.ts +++ b/clients/js/jito_tip_router/instructions/setNewAdmin.ts @@ -48,7 +48,7 @@ export type SetNewAdminInstruction< TAccountNcn extends string | IAccountMeta = string, TAccountNcnAdmin extends string | IAccountMeta = string, TAccountNewAdmin extends string | IAccountMeta = string, - TAccountRestakingProgramId extends string | IAccountMeta = string, + TAccountRestakingProgram extends string | IAccountMeta = string, TRemainingAccounts extends readonly IAccountMeta[] = [], > = IInstruction & IInstructionWithData & @@ -65,9 +65,9 @@ export type SetNewAdminInstruction< TAccountNewAdmin extends string ? ReadonlyAccount : TAccountNewAdmin, - TAccountRestakingProgramId extends string - ? ReadonlyAccount - : TAccountRestakingProgramId, + TAccountRestakingProgram extends string + ? ReadonlyAccount + : TAccountRestakingProgram, ...TRemainingAccounts, ] >; @@ -111,13 +111,13 @@ export type SetNewAdminInput< TAccountNcn extends string = string, TAccountNcnAdmin extends string = string, TAccountNewAdmin extends string = string, - TAccountRestakingProgramId extends string = string, + TAccountRestakingProgram extends string = string, > = { config: Address; ncn: Address; ncnAdmin: TransactionSigner; newAdmin: Address; - restakingProgramId: Address; + restakingProgram: Address; role: SetNewAdminInstructionDataArgs['role']; }; @@ -126,7 +126,7 @@ export function getSetNewAdminInstruction< TAccountNcn extends string, TAccountNcnAdmin extends string, TAccountNewAdmin extends string, - TAccountRestakingProgramId extends string, + TAccountRestakingProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( input: SetNewAdminInput< @@ -134,7 +134,7 @@ export function getSetNewAdminInstruction< TAccountNcn, TAccountNcnAdmin, TAccountNewAdmin, - TAccountRestakingProgramId + TAccountRestakingProgram >, config?: { programAddress?: TProgramAddress } ): SetNewAdminInstruction< @@ -143,7 +143,7 @@ export function getSetNewAdminInstruction< TAccountNcn, TAccountNcnAdmin, TAccountNewAdmin, - TAccountRestakingProgramId + TAccountRestakingProgram > { // Program address. const programAddress = @@ -155,8 +155,8 @@ export function getSetNewAdminInstruction< ncn: { value: input.ncn ?? null, isWritable: false }, ncnAdmin: { value: input.ncnAdmin ?? null, isWritable: false }, newAdmin: { value: input.newAdmin ?? null, isWritable: false }, - restakingProgramId: { - value: input.restakingProgramId ?? null, + restakingProgram: { + value: input.restakingProgram ?? null, isWritable: false, }, }; @@ -175,7 +175,7 @@ export function getSetNewAdminInstruction< getAccountMeta(accounts.ncn), getAccountMeta(accounts.ncnAdmin), getAccountMeta(accounts.newAdmin), - getAccountMeta(accounts.restakingProgramId), + getAccountMeta(accounts.restakingProgram), ], programAddress, data: getSetNewAdminInstructionDataEncoder().encode( @@ -187,7 +187,7 @@ export function getSetNewAdminInstruction< TAccountNcn, TAccountNcnAdmin, TAccountNewAdmin, - TAccountRestakingProgramId + TAccountRestakingProgram >; return instruction; @@ -203,7 +203,7 @@ export type ParsedSetNewAdminInstruction< ncn: TAccountMetas[1]; ncnAdmin: TAccountMetas[2]; newAdmin: TAccountMetas[3]; - restakingProgramId: TAccountMetas[4]; + restakingProgram: TAccountMetas[4]; }; data: SetNewAdminInstructionData; }; @@ -233,7 +233,7 @@ export function parseSetNewAdminInstruction< ncn: getNextAccount(), ncnAdmin: getNextAccount(), newAdmin: getNextAccount(), - restakingProgramId: getNextAccount(), + restakingProgram: getNextAccount(), }, data: getSetNewAdminInstructionDataDecoder().decode(instruction.data), }; diff --git a/clients/rust/jito_tip_router/src/generated/instructions/admin_update_weight_table.rs b/clients/rust/jito_tip_router/src/generated/instructions/admin_update_weight_table.rs index 0df738f..6de2772 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/admin_update_weight_table.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/admin_update_weight_table.rs @@ -16,7 +16,7 @@ pub struct AdminUpdateWeightTable { pub mint: solana_program::pubkey::Pubkey, - pub restaking_program_id: solana_program::pubkey::Pubkey, + pub restaking_program: solana_program::pubkey::Pubkey, } impl AdminUpdateWeightTable { @@ -48,7 +48,7 @@ impl AdminUpdateWeightTable { self.mint, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - self.restaking_program_id, + self.restaking_program, false, )); accounts.extend_from_slice(remaining_accounts); @@ -98,14 +98,14 @@ pub struct AdminUpdateWeightTableInstructionArgs { /// 1. `[writable]` weight_table /// 2. `[signer]` weight_table_admin /// 3. `[]` mint -/// 4. `[]` restaking_program_id +/// 4. `[]` restaking_program #[derive(Clone, Debug, Default)] pub struct AdminUpdateWeightTableBuilder { ncn: Option, weight_table: Option, weight_table_admin: Option, mint: Option, - restaking_program_id: Option, + restaking_program: Option, ncn_epoch: Option, weight: Option, __remaining_accounts: Vec, @@ -139,11 +139,11 @@ impl AdminUpdateWeightTableBuilder { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: solana_program::pubkey::Pubkey, + restaking_program: solana_program::pubkey::Pubkey, ) -> &mut Self { - self.restaking_program_id = Some(restaking_program_id); + self.restaking_program = Some(restaking_program); self } #[inline(always)] @@ -183,9 +183,9 @@ impl AdminUpdateWeightTableBuilder { .weight_table_admin .expect("weight_table_admin is not set"), mint: self.mint.expect("mint is not set"), - restaking_program_id: self - .restaking_program_id - .expect("restaking_program_id is not set"), + restaking_program: self + .restaking_program + .expect("restaking_program is not set"), }; let args = AdminUpdateWeightTableInstructionArgs { ncn_epoch: self.ncn_epoch.clone().expect("ncn_epoch is not set"), @@ -206,7 +206,7 @@ pub struct AdminUpdateWeightTableCpiAccounts<'a, 'b> { pub mint: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, } /// `admin_update_weight_table` CPI instruction. @@ -222,7 +222,7 @@ pub struct AdminUpdateWeightTableCpi<'a, 'b> { pub mint: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. pub __args: AdminUpdateWeightTableInstructionArgs, } @@ -239,7 +239,7 @@ impl<'a, 'b> AdminUpdateWeightTableCpi<'a, 'b> { weight_table: accounts.weight_table, weight_table_admin: accounts.weight_table_admin, mint: accounts.mint, - restaking_program_id: accounts.restaking_program_id, + restaking_program: accounts.restaking_program, __args: args, } } @@ -294,7 +294,7 @@ impl<'a, 'b> AdminUpdateWeightTableCpi<'a, 'b> { false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - *self.restaking_program_id.key, + *self.restaking_program.key, false, )); remaining_accounts.iter().for_each(|remaining_account| { @@ -321,7 +321,7 @@ impl<'a, 'b> AdminUpdateWeightTableCpi<'a, 'b> { account_infos.push(self.weight_table.clone()); account_infos.push(self.weight_table_admin.clone()); account_infos.push(self.mint.clone()); - account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.restaking_program.clone()); remaining_accounts .iter() .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); @@ -342,7 +342,7 @@ impl<'a, 'b> AdminUpdateWeightTableCpi<'a, 'b> { /// 1. `[writable]` weight_table /// 2. `[signer]` weight_table_admin /// 3. `[]` mint -/// 4. `[]` restaking_program_id +/// 4. `[]` restaking_program #[derive(Clone, Debug)] pub struct AdminUpdateWeightTableCpiBuilder<'a, 'b> { instruction: Box>, @@ -356,7 +356,7 @@ impl<'a, 'b> AdminUpdateWeightTableCpiBuilder<'a, 'b> { weight_table: None, weight_table_admin: None, mint: None, - restaking_program_id: None, + restaking_program: None, ncn_epoch: None, weight: None, __remaining_accounts: Vec::new(), @@ -390,11 +390,11 @@ impl<'a, 'b> AdminUpdateWeightTableCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + restaking_program: &'b solana_program::account_info::AccountInfo<'a>, ) -> &mut Self { - self.instruction.restaking_program_id = Some(restaking_program_id); + self.instruction.restaking_program = Some(restaking_program); self } #[inline(always)] @@ -473,10 +473,10 @@ impl<'a, 'b> AdminUpdateWeightTableCpiBuilder<'a, 'b> { mint: self.instruction.mint.expect("mint is not set"), - restaking_program_id: self + restaking_program: self .instruction - .restaking_program_id - .expect("restaking_program_id is not set"), + .restaking_program + .expect("restaking_program is not set"), __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -493,7 +493,7 @@ struct AdminUpdateWeightTableCpiBuilderInstruction<'a, 'b> { weight_table: Option<&'b solana_program::account_info::AccountInfo<'a>>, weight_table_admin: Option<&'b solana_program::account_info::AccountInfo<'a>>, mint: Option<&'b solana_program::account_info::AccountInfo<'a>>, - restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, ncn_epoch: Option, weight: Option, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs index 520d8b9..d19e7ae 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs @@ -20,7 +20,7 @@ pub struct InitializeEpochSnapshot { pub payer: solana_program::pubkey::Pubkey, - pub restaking_program_id: solana_program::pubkey::Pubkey, + pub restaking_program: solana_program::pubkey::Pubkey, pub system_program: solana_program::pubkey::Pubkey, } @@ -62,7 +62,7 @@ impl InitializeEpochSnapshot { self.payer, true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - self.restaking_program_id, + self.restaking_program, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -117,7 +117,7 @@ pub struct InitializeEpochSnapshotInstructionArgs { /// 3. `[]` weight_table /// 4. `[writable]` epoch_snapshot /// 5. `[writable, signer]` payer -/// 6. `[]` restaking_program_id +/// 6. `[]` restaking_program /// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) #[derive(Clone, Debug, Default)] pub struct InitializeEpochSnapshotBuilder { @@ -127,7 +127,7 @@ pub struct InitializeEpochSnapshotBuilder { weight_table: Option, epoch_snapshot: Option, payer: Option, - restaking_program_id: Option, + restaking_program: Option, system_program: Option, first_slot_of_ncn_epoch: Option, __remaining_accounts: Vec, @@ -171,11 +171,11 @@ impl InitializeEpochSnapshotBuilder { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: solana_program::pubkey::Pubkey, + restaking_program: solana_program::pubkey::Pubkey, ) -> &mut Self { - self.restaking_program_id = Some(restaking_program_id); + self.restaking_program = Some(restaking_program); self } /// `[optional account, default to '11111111111111111111111111111111']` @@ -217,9 +217,9 @@ impl InitializeEpochSnapshotBuilder { weight_table: self.weight_table.expect("weight_table is not set"), epoch_snapshot: self.epoch_snapshot.expect("epoch_snapshot is not set"), payer: self.payer.expect("payer is not set"), - restaking_program_id: self - .restaking_program_id - .expect("restaking_program_id is not set"), + restaking_program: self + .restaking_program + .expect("restaking_program is not set"), system_program: self .system_program .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), @@ -246,7 +246,7 @@ pub struct InitializeEpochSnapshotCpiAccounts<'a, 'b> { pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, } @@ -268,7 +268,7 @@ pub struct InitializeEpochSnapshotCpi<'a, 'b> { pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. @@ -289,7 +289,7 @@ impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { weight_table: accounts.weight_table, epoch_snapshot: accounts.epoch_snapshot, payer: accounts.payer, - restaking_program_id: accounts.restaking_program_id, + restaking_program: accounts.restaking_program, system_program: accounts.system_program, __args: args, } @@ -353,7 +353,7 @@ impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - *self.restaking_program_id.key, + *self.restaking_program.key, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -386,7 +386,7 @@ impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { account_infos.push(self.weight_table.clone()); account_infos.push(self.epoch_snapshot.clone()); account_infos.push(self.payer.clone()); - account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.restaking_program.clone()); account_infos.push(self.system_program.clone()); remaining_accounts .iter() @@ -410,7 +410,7 @@ impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { /// 3. `[]` weight_table /// 4. `[writable]` epoch_snapshot /// 5. `[writable, signer]` payer -/// 6. `[]` restaking_program_id +/// 6. `[]` restaking_program /// 7. `[]` system_program #[derive(Clone, Debug)] pub struct InitializeEpochSnapshotCpiBuilder<'a, 'b> { @@ -427,7 +427,7 @@ impl<'a, 'b> InitializeEpochSnapshotCpiBuilder<'a, 'b> { weight_table: None, epoch_snapshot: None, payer: None, - restaking_program_id: None, + restaking_program: None, system_program: None, first_slot_of_ncn_epoch: None, __remaining_accounts: Vec::new(), @@ -477,11 +477,11 @@ impl<'a, 'b> InitializeEpochSnapshotCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + restaking_program: &'b solana_program::account_info::AccountInfo<'a>, ) -> &mut Self { - self.instruction.restaking_program_id = Some(restaking_program_id); + self.instruction.restaking_program = Some(restaking_program); self } #[inline(always)] @@ -566,10 +566,10 @@ impl<'a, 'b> InitializeEpochSnapshotCpiBuilder<'a, 'b> { payer: self.instruction.payer.expect("payer is not set"), - restaking_program_id: self + restaking_program: self .instruction - .restaking_program_id - .expect("restaking_program_id is not set"), + .restaking_program + .expect("restaking_program is not set"), system_program: self .instruction @@ -593,7 +593,7 @@ struct InitializeEpochSnapshotCpiBuilderInstruction<'a, 'b> { weight_table: Option<&'b solana_program::account_info::AccountInfo<'a>>, epoch_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, - restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, first_slot_of_ncn_epoch: Option, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_n_c_n_config.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_n_c_n_config.rs index 1806829..6c83fd6 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/initialize_n_c_n_config.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_n_c_n_config.rs @@ -20,7 +20,7 @@ pub struct InitializeNCNConfig { pub tie_breaker_admin: solana_program::pubkey::Pubkey, - pub restaking_program_id: solana_program::pubkey::Pubkey, + pub restaking_program: solana_program::pubkey::Pubkey, pub system_program: solana_program::pubkey::Pubkey, } @@ -63,7 +63,7 @@ impl InitializeNCNConfig { false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - self.restaking_program_id, + self.restaking_program, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -120,7 +120,7 @@ pub struct InitializeNCNConfigInstructionArgs { /// 3. `[signer]` ncn_admin /// 4. `[]` fee_wallet /// 5. `[]` tie_breaker_admin -/// 6. `[]` restaking_program_id +/// 6. `[]` restaking_program /// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) #[derive(Clone, Debug, Default)] pub struct InitializeNCNConfigBuilder { @@ -130,7 +130,7 @@ pub struct InitializeNCNConfigBuilder { ncn_admin: Option, fee_wallet: Option, tie_breaker_admin: Option, - restaking_program_id: Option, + restaking_program: Option, system_program: Option, dao_fee_bps: Option, ncn_fee_bps: Option, @@ -179,11 +179,11 @@ impl InitializeNCNConfigBuilder { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: solana_program::pubkey::Pubkey, + restaking_program: solana_program::pubkey::Pubkey, ) -> &mut Self { - self.restaking_program_id = Some(restaking_program_id); + self.restaking_program = Some(restaking_program); self } /// `[optional account, default to '11111111111111111111111111111111']` @@ -236,9 +236,9 @@ impl InitializeNCNConfigBuilder { tie_breaker_admin: self .tie_breaker_admin .expect("tie_breaker_admin is not set"), - restaking_program_id: self - .restaking_program_id - .expect("restaking_program_id is not set"), + restaking_program: self + .restaking_program + .expect("restaking_program is not set"), system_program: self .system_program .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), @@ -270,7 +270,7 @@ pub struct InitializeNCNConfigCpiAccounts<'a, 'b> { pub tie_breaker_admin: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, } @@ -292,7 +292,7 @@ pub struct InitializeNCNConfigCpi<'a, 'b> { pub tie_breaker_admin: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. @@ -313,7 +313,7 @@ impl<'a, 'b> InitializeNCNConfigCpi<'a, 'b> { ncn_admin: accounts.ncn_admin, fee_wallet: accounts.fee_wallet, tie_breaker_admin: accounts.tie_breaker_admin, - restaking_program_id: accounts.restaking_program_id, + restaking_program: accounts.restaking_program, system_program: accounts.system_program, __args: args, } @@ -377,7 +377,7 @@ impl<'a, 'b> InitializeNCNConfigCpi<'a, 'b> { false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - *self.restaking_program_id.key, + *self.restaking_program.key, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -410,7 +410,7 @@ impl<'a, 'b> InitializeNCNConfigCpi<'a, 'b> { account_infos.push(self.ncn_admin.clone()); account_infos.push(self.fee_wallet.clone()); account_infos.push(self.tie_breaker_admin.clone()); - account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.restaking_program.clone()); account_infos.push(self.system_program.clone()); remaining_accounts .iter() @@ -434,7 +434,7 @@ impl<'a, 'b> InitializeNCNConfigCpi<'a, 'b> { /// 3. `[signer]` ncn_admin /// 4. `[]` fee_wallet /// 5. `[]` tie_breaker_admin -/// 6. `[]` restaking_program_id +/// 6. `[]` restaking_program /// 7. `[]` system_program #[derive(Clone, Debug)] pub struct InitializeNCNConfigCpiBuilder<'a, 'b> { @@ -451,7 +451,7 @@ impl<'a, 'b> InitializeNCNConfigCpiBuilder<'a, 'b> { ncn_admin: None, fee_wallet: None, tie_breaker_admin: None, - restaking_program_id: None, + restaking_program: None, system_program: None, dao_fee_bps: None, ncn_fee_bps: None, @@ -506,11 +506,11 @@ impl<'a, 'b> InitializeNCNConfigCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + restaking_program: &'b solana_program::account_info::AccountInfo<'a>, ) -> &mut Self { - self.instruction.restaking_program_id = Some(restaking_program_id); + self.instruction.restaking_program = Some(restaking_program); self } #[inline(always)] @@ -615,10 +615,10 @@ impl<'a, 'b> InitializeNCNConfigCpiBuilder<'a, 'b> { .tie_breaker_admin .expect("tie_breaker_admin is not set"), - restaking_program_id: self + restaking_program: self .instruction - .restaking_program_id - .expect("restaking_program_id is not set"), + .restaking_program + .expect("restaking_program is not set"), system_program: self .instruction @@ -642,7 +642,7 @@ struct InitializeNCNConfigCpiBuilderInstruction<'a, 'b> { ncn_admin: Option<&'b solana_program::account_info::AccountInfo<'a>>, fee_wallet: Option<&'b solana_program::account_info::AccountInfo<'a>>, tie_breaker_admin: Option<&'b solana_program::account_info::AccountInfo<'a>>, - restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, dao_fee_bps: Option, ncn_fee_bps: Option, diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_operator_snapshot.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_operator_snapshot.rs index c367681..f28c3f0 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/initialize_operator_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_operator_snapshot.rs @@ -24,7 +24,7 @@ pub struct InitializeOperatorSnapshot { pub payer: solana_program::pubkey::Pubkey, - pub restaking_program_id: solana_program::pubkey::Pubkey, + pub restaking_program: solana_program::pubkey::Pubkey, pub system_program: solana_program::pubkey::Pubkey, } @@ -74,7 +74,7 @@ impl InitializeOperatorSnapshot { self.payer, true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - self.restaking_program_id, + self.restaking_program, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -131,7 +131,7 @@ pub struct InitializeOperatorSnapshotInstructionArgs { /// 5. `[writable]` epoch_snapshot /// 6. `[writable]` operator_snapshot /// 7. `[writable, signer]` payer -/// 8. `[]` restaking_program_id +/// 8. `[]` restaking_program /// 9. `[optional]` system_program (default to `11111111111111111111111111111111`) #[derive(Clone, Debug, Default)] pub struct InitializeOperatorSnapshotBuilder { @@ -143,7 +143,7 @@ pub struct InitializeOperatorSnapshotBuilder { epoch_snapshot: Option, operator_snapshot: Option, payer: Option, - restaking_program_id: Option, + restaking_program: Option, system_program: Option, first_slot_of_ncn_epoch: Option, __remaining_accounts: Vec, @@ -203,11 +203,11 @@ impl InitializeOperatorSnapshotBuilder { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: solana_program::pubkey::Pubkey, + restaking_program: solana_program::pubkey::Pubkey, ) -> &mut Self { - self.restaking_program_id = Some(restaking_program_id); + self.restaking_program = Some(restaking_program); self } /// `[optional account, default to '11111111111111111111111111111111']` @@ -255,9 +255,9 @@ impl InitializeOperatorSnapshotBuilder { .operator_snapshot .expect("operator_snapshot is not set"), payer: self.payer.expect("payer is not set"), - restaking_program_id: self - .restaking_program_id - .expect("restaking_program_id is not set"), + restaking_program: self + .restaking_program + .expect("restaking_program is not set"), system_program: self .system_program .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), @@ -288,7 +288,7 @@ pub struct InitializeOperatorSnapshotCpiAccounts<'a, 'b> { pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, } @@ -314,7 +314,7 @@ pub struct InitializeOperatorSnapshotCpi<'a, 'b> { pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. @@ -337,7 +337,7 @@ impl<'a, 'b> InitializeOperatorSnapshotCpi<'a, 'b> { epoch_snapshot: accounts.epoch_snapshot, operator_snapshot: accounts.operator_snapshot, payer: accounts.payer, - restaking_program_id: accounts.restaking_program_id, + restaking_program: accounts.restaking_program, system_program: accounts.system_program, __args: args, } @@ -409,7 +409,7 @@ impl<'a, 'b> InitializeOperatorSnapshotCpi<'a, 'b> { true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - *self.restaking_program_id.key, + *self.restaking_program.key, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -444,7 +444,7 @@ impl<'a, 'b> InitializeOperatorSnapshotCpi<'a, 'b> { account_infos.push(self.epoch_snapshot.clone()); account_infos.push(self.operator_snapshot.clone()); account_infos.push(self.payer.clone()); - account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.restaking_program.clone()); account_infos.push(self.system_program.clone()); remaining_accounts .iter() @@ -470,7 +470,7 @@ impl<'a, 'b> InitializeOperatorSnapshotCpi<'a, 'b> { /// 5. `[writable]` epoch_snapshot /// 6. `[writable]` operator_snapshot /// 7. `[writable, signer]` payer -/// 8. `[]` restaking_program_id +/// 8. `[]` restaking_program /// 9. `[]` system_program #[derive(Clone, Debug)] pub struct InitializeOperatorSnapshotCpiBuilder<'a, 'b> { @@ -489,7 +489,7 @@ impl<'a, 'b> InitializeOperatorSnapshotCpiBuilder<'a, 'b> { epoch_snapshot: None, operator_snapshot: None, payer: None, - restaking_program_id: None, + restaking_program: None, system_program: None, first_slot_of_ncn_epoch: None, __remaining_accounts: Vec::new(), @@ -555,11 +555,11 @@ impl<'a, 'b> InitializeOperatorSnapshotCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + restaking_program: &'b solana_program::account_info::AccountInfo<'a>, ) -> &mut Self { - self.instruction.restaking_program_id = Some(restaking_program_id); + self.instruction.restaking_program = Some(restaking_program); self } #[inline(always)] @@ -651,10 +651,10 @@ impl<'a, 'b> InitializeOperatorSnapshotCpiBuilder<'a, 'b> { payer: self.instruction.payer.expect("payer is not set"), - restaking_program_id: self + restaking_program: self .instruction - .restaking_program_id - .expect("restaking_program_id is not set"), + .restaking_program + .expect("restaking_program is not set"), system_program: self .instruction @@ -680,7 +680,7 @@ struct InitializeOperatorSnapshotCpiBuilderInstruction<'a, 'b> { epoch_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, operator_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, - restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, first_slot_of_ncn_epoch: Option, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs index 2652400..840bc41 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs @@ -34,7 +34,9 @@ pub struct InitializeVaultOperatorDelegationSnapshot { pub payer: solana_program::pubkey::Pubkey, - pub restaking_program_id: solana_program::pubkey::Pubkey, + pub vault_program: solana_program::pubkey::Pubkey, + + pub restaking_program: solana_program::pubkey::Pubkey, pub system_program: solana_program::pubkey::Pubkey, } @@ -52,7 +54,7 @@ impl InitializeVaultOperatorDelegationSnapshot { args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, remaining_accounts: &[solana_program::instruction::AccountMeta], ) -> solana_program::instruction::Instruction { - let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(16 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new_readonly( self.ncn_config, false, @@ -103,7 +105,11 @@ impl InitializeVaultOperatorDelegationSnapshot { self.payer, true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - self.restaking_program_id, + self.vault_program, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.restaking_program, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -165,8 +171,9 @@ pub struct InitializeVaultOperatorDelegationSnapshotInstructionArgs { /// 10. `[writable]` operator_snapshot /// 11. `[writable]` vault_operator_delegation_snapshot /// 12. `[writable, signer]` payer -/// 13. `[]` restaking_program_id -/// 14. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 13. `[]` vault_program +/// 14. `[]` restaking_program +/// 15. `[optional]` system_program (default to `11111111111111111111111111111111`) #[derive(Clone, Debug, Default)] pub struct InitializeVaultOperatorDelegationSnapshotBuilder { ncn_config: Option, @@ -182,7 +189,8 @@ pub struct InitializeVaultOperatorDelegationSnapshotBuilder { operator_snapshot: Option, vault_operator_delegation_snapshot: Option, payer: Option, - restaking_program_id: Option, + vault_program: Option, + restaking_program: Option, system_program: Option, first_slot_of_ncn_epoch: Option, __remaining_accounts: Vec, @@ -276,11 +284,16 @@ impl InitializeVaultOperatorDelegationSnapshotBuilder { self } #[inline(always)] - pub fn restaking_program_id( + pub fn vault_program(&mut self, vault_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.vault_program = Some(vault_program); + self + } + #[inline(always)] + pub fn restaking_program( &mut self, - restaking_program_id: solana_program::pubkey::Pubkey, + restaking_program: solana_program::pubkey::Pubkey, ) -> &mut Self { - self.restaking_program_id = Some(restaking_program_id); + self.restaking_program = Some(restaking_program); self } /// `[optional account, default to '11111111111111111111111111111111']` @@ -335,9 +348,10 @@ impl InitializeVaultOperatorDelegationSnapshotBuilder { .vault_operator_delegation_snapshot .expect("vault_operator_delegation_snapshot is not set"), payer: self.payer.expect("payer is not set"), - restaking_program_id: self - .restaking_program_id - .expect("restaking_program_id is not set"), + vault_program: self.vault_program.expect("vault_program is not set"), + restaking_program: self + .restaking_program + .expect("restaking_program is not set"), system_program: self .system_program .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), @@ -378,7 +392,9 @@ pub struct InitializeVaultOperatorDelegationSnapshotCpiAccounts<'a, 'b> { pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub vault_program: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, } @@ -414,7 +430,9 @@ pub struct InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub vault_program: &'b solana_program::account_info::AccountInfo<'a>, + + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. @@ -442,7 +460,8 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { operator_snapshot: accounts.operator_snapshot, vault_operator_delegation_snapshot: accounts.vault_operator_delegation_snapshot, payer: accounts.payer, - restaking_program_id: accounts.restaking_program_id, + vault_program: accounts.vault_program, + restaking_program: accounts.restaking_program, system_program: accounts.system_program, __args: args, } @@ -480,7 +499,7 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { bool, )], ) -> solana_program::entrypoint::ProgramResult { - let mut accounts = Vec::with_capacity(15 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(16 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new_readonly( *self.ncn_config.key, false, @@ -534,7 +553,11 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - *self.restaking_program_id.key, + *self.vault_program.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.restaking_program.key, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -559,7 +582,7 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { accounts, data, }; - let mut account_infos = Vec::with_capacity(15 + 1 + remaining_accounts.len()); + let mut account_infos = Vec::with_capacity(16 + 1 + remaining_accounts.len()); account_infos.push(self.__program.clone()); account_infos.push(self.ncn_config.clone()); account_infos.push(self.restaking_config.clone()); @@ -574,7 +597,8 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { account_infos.push(self.operator_snapshot.clone()); account_infos.push(self.vault_operator_delegation_snapshot.clone()); account_infos.push(self.payer.clone()); - account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.vault_program.clone()); + account_infos.push(self.restaking_program.clone()); account_infos.push(self.system_program.clone()); remaining_accounts .iter() @@ -605,8 +629,9 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { /// 10. `[writable]` operator_snapshot /// 11. `[writable]` vault_operator_delegation_snapshot /// 12. `[writable, signer]` payer -/// 13. `[]` restaking_program_id -/// 14. `[]` system_program +/// 13. `[]` vault_program +/// 14. `[]` restaking_program +/// 15. `[]` system_program #[derive(Clone, Debug)] pub struct InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { instruction: Box>, @@ -630,7 +655,8 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { operator_snapshot: None, vault_operator_delegation_snapshot: None, payer: None, - restaking_program_id: None, + vault_program: None, + restaking_program: None, system_program: None, first_slot_of_ncn_epoch: None, __remaining_accounts: Vec::new(), @@ -735,11 +761,19 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn restaking_program_id( + pub fn vault_program( &mut self, - restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + vault_program: &'b solana_program::account_info::AccountInfo<'a>, ) -> &mut Self { - self.instruction.restaking_program_id = Some(restaking_program_id); + self.instruction.vault_program = Some(vault_program); + self + } + #[inline(always)] + pub fn restaking_program( + &mut self, + restaking_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.restaking_program = Some(restaking_program); self } #[inline(always)] @@ -853,10 +887,15 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { payer: self.instruction.payer.expect("payer is not set"), - restaking_program_id: self + vault_program: self + .instruction + .vault_program + .expect("vault_program is not set"), + + restaking_program: self .instruction - .restaking_program_id - .expect("restaking_program_id is not set"), + .restaking_program + .expect("restaking_program is not set"), system_program: self .instruction @@ -887,7 +926,8 @@ struct InitializeVaultOperatorDelegationSnapshotCpiBuilderInstruction<'a, 'b> { operator_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, vault_operator_delegation_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, - restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, first_slot_of_ncn_epoch: Option, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_weight_table.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_weight_table.rs index 1c703fc..b8e20d3 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/initialize_weight_table.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_weight_table.rs @@ -18,7 +18,7 @@ pub struct InitializeWeightTable { pub payer: solana_program::pubkey::Pubkey, - pub restaking_program_id: solana_program::pubkey::Pubkey, + pub restaking_program: solana_program::pubkey::Pubkey, pub system_program: solana_program::pubkey::Pubkey, } @@ -56,7 +56,7 @@ impl InitializeWeightTable { self.payer, true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - self.restaking_program_id, + self.restaking_program, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -110,7 +110,7 @@ pub struct InitializeWeightTableInstructionArgs { /// 2. `[]` ncn /// 3. `[writable]` weight_table /// 4. `[writable, signer]` payer -/// 5. `[]` restaking_program_id +/// 5. `[]` restaking_program /// 6. `[optional]` system_program (default to `11111111111111111111111111111111`) #[derive(Clone, Debug, Default)] pub struct InitializeWeightTableBuilder { @@ -119,7 +119,7 @@ pub struct InitializeWeightTableBuilder { ncn: Option, weight_table: Option, payer: Option, - restaking_program_id: Option, + restaking_program: Option, system_program: Option, first_slot_of_ncn_epoch: Option, __remaining_accounts: Vec, @@ -158,11 +158,11 @@ impl InitializeWeightTableBuilder { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: solana_program::pubkey::Pubkey, + restaking_program: solana_program::pubkey::Pubkey, ) -> &mut Self { - self.restaking_program_id = Some(restaking_program_id); + self.restaking_program = Some(restaking_program); self } /// `[optional account, default to '11111111111111111111111111111111']` @@ -203,9 +203,9 @@ impl InitializeWeightTableBuilder { ncn: self.ncn.expect("ncn is not set"), weight_table: self.weight_table.expect("weight_table is not set"), payer: self.payer.expect("payer is not set"), - restaking_program_id: self - .restaking_program_id - .expect("restaking_program_id is not set"), + restaking_program: self + .restaking_program + .expect("restaking_program is not set"), system_program: self .system_program .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), @@ -230,7 +230,7 @@ pub struct InitializeWeightTableCpiAccounts<'a, 'b> { pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, } @@ -250,7 +250,7 @@ pub struct InitializeWeightTableCpi<'a, 'b> { pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. @@ -270,7 +270,7 @@ impl<'a, 'b> InitializeWeightTableCpi<'a, 'b> { ncn: accounts.ncn, weight_table: accounts.weight_table, payer: accounts.payer, - restaking_program_id: accounts.restaking_program_id, + restaking_program: accounts.restaking_program, system_program: accounts.system_program, __args: args, } @@ -330,7 +330,7 @@ impl<'a, 'b> InitializeWeightTableCpi<'a, 'b> { true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - *self.restaking_program_id.key, + *self.restaking_program.key, false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -362,7 +362,7 @@ impl<'a, 'b> InitializeWeightTableCpi<'a, 'b> { account_infos.push(self.ncn.clone()); account_infos.push(self.weight_table.clone()); account_infos.push(self.payer.clone()); - account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.restaking_program.clone()); account_infos.push(self.system_program.clone()); remaining_accounts .iter() @@ -385,7 +385,7 @@ impl<'a, 'b> InitializeWeightTableCpi<'a, 'b> { /// 2. `[]` ncn /// 3. `[writable]` weight_table /// 4. `[writable, signer]` payer -/// 5. `[]` restaking_program_id +/// 5. `[]` restaking_program /// 6. `[]` system_program #[derive(Clone, Debug)] pub struct InitializeWeightTableCpiBuilder<'a, 'b> { @@ -401,7 +401,7 @@ impl<'a, 'b> InitializeWeightTableCpiBuilder<'a, 'b> { ncn: None, weight_table: None, payer: None, - restaking_program_id: None, + restaking_program: None, system_program: None, first_slot_of_ncn_epoch: None, __remaining_accounts: Vec::new(), @@ -443,11 +443,11 @@ impl<'a, 'b> InitializeWeightTableCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + restaking_program: &'b solana_program::account_info::AccountInfo<'a>, ) -> &mut Self { - self.instruction.restaking_program_id = Some(restaking_program_id); + self.instruction.restaking_program = Some(restaking_program); self } #[inline(always)] @@ -527,10 +527,10 @@ impl<'a, 'b> InitializeWeightTableCpiBuilder<'a, 'b> { payer: self.instruction.payer.expect("payer is not set"), - restaking_program_id: self + restaking_program: self .instruction - .restaking_program_id - .expect("restaking_program_id is not set"), + .restaking_program + .expect("restaking_program is not set"), system_program: self .instruction @@ -553,7 +553,7 @@ struct InitializeWeightTableCpiBuilderInstruction<'a, 'b> { ncn: Option<&'b solana_program::account_info::AccountInfo<'a>>, weight_table: Option<&'b solana_program::account_info::AccountInfo<'a>>, payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, - restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, first_slot_of_ncn_epoch: Option, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. diff --git a/clients/rust/jito_tip_router/src/generated/instructions/set_config_fees.rs b/clients/rust/jito_tip_router/src/generated/instructions/set_config_fees.rs index 71a4cb2..877c04f 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/set_config_fees.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/set_config_fees.rs @@ -17,7 +17,7 @@ pub struct SetConfigFees { pub ncn_admin: solana_program::pubkey::Pubkey, - pub restaking_program_id: solana_program::pubkey::Pubkey, + pub restaking_program: solana_program::pubkey::Pubkey, } impl SetConfigFees { @@ -50,7 +50,7 @@ impl SetConfigFees { true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - self.restaking_program_id, + self.restaking_program, false, )); accounts.extend_from_slice(remaining_accounts); @@ -100,14 +100,14 @@ pub struct SetConfigFeesInstructionArgs { /// 1. `[writable]` config /// 2. `[]` ncn /// 3. `[signer]` ncn_admin -/// 4. `[]` restaking_program_id +/// 4. `[]` restaking_program #[derive(Clone, Debug, Default)] pub struct SetConfigFeesBuilder { restaking_config: Option, config: Option, ncn: Option, ncn_admin: Option, - restaking_program_id: Option, + restaking_program: Option, new_dao_fee_bps: Option, new_ncn_fee_bps: Option, new_block_engine_fee_bps: Option, @@ -143,11 +143,11 @@ impl SetConfigFeesBuilder { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: solana_program::pubkey::Pubkey, + restaking_program: solana_program::pubkey::Pubkey, ) -> &mut Self { - self.restaking_program_id = Some(restaking_program_id); + self.restaking_program = Some(restaking_program); self } /// `[optional argument]` @@ -199,9 +199,9 @@ impl SetConfigFeesBuilder { config: self.config.expect("config is not set"), ncn: self.ncn.expect("ncn is not set"), ncn_admin: self.ncn_admin.expect("ncn_admin is not set"), - restaking_program_id: self - .restaking_program_id - .expect("restaking_program_id is not set"), + restaking_program: self + .restaking_program + .expect("restaking_program is not set"), }; let args = SetConfigFeesInstructionArgs { new_dao_fee_bps: self.new_dao_fee_bps.clone(), @@ -224,7 +224,7 @@ pub struct SetConfigFeesCpiAccounts<'a, 'b> { pub ncn_admin: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, } /// `set_config_fees` CPI instruction. @@ -240,7 +240,7 @@ pub struct SetConfigFeesCpi<'a, 'b> { pub ncn_admin: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. pub __args: SetConfigFeesInstructionArgs, } @@ -257,7 +257,7 @@ impl<'a, 'b> SetConfigFeesCpi<'a, 'b> { config: accounts.config, ncn: accounts.ncn, ncn_admin: accounts.ncn_admin, - restaking_program_id: accounts.restaking_program_id, + restaking_program: accounts.restaking_program, __args: args, } } @@ -312,7 +312,7 @@ impl<'a, 'b> SetConfigFeesCpi<'a, 'b> { true, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - *self.restaking_program_id.key, + *self.restaking_program.key, false, )); remaining_accounts.iter().for_each(|remaining_account| { @@ -337,7 +337,7 @@ impl<'a, 'b> SetConfigFeesCpi<'a, 'b> { account_infos.push(self.config.clone()); account_infos.push(self.ncn.clone()); account_infos.push(self.ncn_admin.clone()); - account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.restaking_program.clone()); remaining_accounts .iter() .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); @@ -358,7 +358,7 @@ impl<'a, 'b> SetConfigFeesCpi<'a, 'b> { /// 1. `[writable]` config /// 2. `[]` ncn /// 3. `[signer]` ncn_admin -/// 4. `[]` restaking_program_id +/// 4. `[]` restaking_program #[derive(Clone, Debug)] pub struct SetConfigFeesCpiBuilder<'a, 'b> { instruction: Box>, @@ -372,7 +372,7 @@ impl<'a, 'b> SetConfigFeesCpiBuilder<'a, 'b> { config: None, ncn: None, ncn_admin: None, - restaking_program_id: None, + restaking_program: None, new_dao_fee_bps: None, new_ncn_fee_bps: None, new_block_engine_fee_bps: None, @@ -411,11 +411,11 @@ impl<'a, 'b> SetConfigFeesCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + restaking_program: &'b solana_program::account_info::AccountInfo<'a>, ) -> &mut Self { - self.instruction.restaking_program_id = Some(restaking_program_id); + self.instruction.restaking_program = Some(restaking_program); self } /// `[optional argument]` @@ -503,10 +503,10 @@ impl<'a, 'b> SetConfigFeesCpiBuilder<'a, 'b> { ncn_admin: self.instruction.ncn_admin.expect("ncn_admin is not set"), - restaking_program_id: self + restaking_program: self .instruction - .restaking_program_id - .expect("restaking_program_id is not set"), + .restaking_program + .expect("restaking_program is not set"), __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -523,7 +523,7 @@ struct SetConfigFeesCpiBuilderInstruction<'a, 'b> { config: Option<&'b solana_program::account_info::AccountInfo<'a>>, ncn: Option<&'b solana_program::account_info::AccountInfo<'a>>, ncn_admin: Option<&'b solana_program::account_info::AccountInfo<'a>>, - restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, new_dao_fee_bps: Option, new_ncn_fee_bps: Option, new_block_engine_fee_bps: Option, diff --git a/clients/rust/jito_tip_router/src/generated/instructions/set_new_admin.rs b/clients/rust/jito_tip_router/src/generated/instructions/set_new_admin.rs index c46086d..66b1443 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/set_new_admin.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/set_new_admin.rs @@ -18,7 +18,7 @@ pub struct SetNewAdmin { pub new_admin: solana_program::pubkey::Pubkey, - pub restaking_program_id: solana_program::pubkey::Pubkey, + pub restaking_program: solana_program::pubkey::Pubkey, } impl SetNewAdmin { @@ -51,7 +51,7 @@ impl SetNewAdmin { false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - self.restaking_program_id, + self.restaking_program, false, )); accounts.extend_from_slice(remaining_accounts); @@ -98,14 +98,14 @@ pub struct SetNewAdminInstructionArgs { /// 1. `[]` ncn /// 2. `[signer]` ncn_admin /// 3. `[]` new_admin -/// 4. `[]` restaking_program_id +/// 4. `[]` restaking_program #[derive(Clone, Debug, Default)] pub struct SetNewAdminBuilder { config: Option, ncn: Option, ncn_admin: Option, new_admin: Option, - restaking_program_id: Option, + restaking_program: Option, role: Option, __remaining_accounts: Vec, } @@ -135,11 +135,11 @@ impl SetNewAdminBuilder { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: solana_program::pubkey::Pubkey, + restaking_program: solana_program::pubkey::Pubkey, ) -> &mut Self { - self.restaking_program_id = Some(restaking_program_id); + self.restaking_program = Some(restaking_program); self } #[inline(always)] @@ -172,9 +172,9 @@ impl SetNewAdminBuilder { ncn: self.ncn.expect("ncn is not set"), ncn_admin: self.ncn_admin.expect("ncn_admin is not set"), new_admin: self.new_admin.expect("new_admin is not set"), - restaking_program_id: self - .restaking_program_id - .expect("restaking_program_id is not set"), + restaking_program: self + .restaking_program + .expect("restaking_program is not set"), }; let args = SetNewAdminInstructionArgs { role: self.role.clone().expect("role is not set"), @@ -194,7 +194,7 @@ pub struct SetNewAdminCpiAccounts<'a, 'b> { pub new_admin: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, } /// `set_new_admin` CPI instruction. @@ -210,7 +210,7 @@ pub struct SetNewAdminCpi<'a, 'b> { pub new_admin: &'b solana_program::account_info::AccountInfo<'a>, - pub restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. pub __args: SetNewAdminInstructionArgs, } @@ -227,7 +227,7 @@ impl<'a, 'b> SetNewAdminCpi<'a, 'b> { ncn: accounts.ncn, ncn_admin: accounts.ncn_admin, new_admin: accounts.new_admin, - restaking_program_id: accounts.restaking_program_id, + restaking_program: accounts.restaking_program, __args: args, } } @@ -282,7 +282,7 @@ impl<'a, 'b> SetNewAdminCpi<'a, 'b> { false, )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( - *self.restaking_program_id.key, + *self.restaking_program.key, false, )); remaining_accounts.iter().for_each(|remaining_account| { @@ -307,7 +307,7 @@ impl<'a, 'b> SetNewAdminCpi<'a, 'b> { account_infos.push(self.ncn.clone()); account_infos.push(self.ncn_admin.clone()); account_infos.push(self.new_admin.clone()); - account_infos.push(self.restaking_program_id.clone()); + account_infos.push(self.restaking_program.clone()); remaining_accounts .iter() .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); @@ -328,7 +328,7 @@ impl<'a, 'b> SetNewAdminCpi<'a, 'b> { /// 1. `[]` ncn /// 2. `[signer]` ncn_admin /// 3. `[]` new_admin -/// 4. `[]` restaking_program_id +/// 4. `[]` restaking_program #[derive(Clone, Debug)] pub struct SetNewAdminCpiBuilder<'a, 'b> { instruction: Box>, @@ -342,7 +342,7 @@ impl<'a, 'b> SetNewAdminCpiBuilder<'a, 'b> { ncn: None, ncn_admin: None, new_admin: None, - restaking_program_id: None, + restaking_program: None, role: None, __remaining_accounts: Vec::new(), }); @@ -378,11 +378,11 @@ impl<'a, 'b> SetNewAdminCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn restaking_program_id( + pub fn restaking_program( &mut self, - restaking_program_id: &'b solana_program::account_info::AccountInfo<'a>, + restaking_program: &'b solana_program::account_info::AccountInfo<'a>, ) -> &mut Self { - self.instruction.restaking_program_id = Some(restaking_program_id); + self.instruction.restaking_program = Some(restaking_program); self } #[inline(always)] @@ -445,10 +445,10 @@ impl<'a, 'b> SetNewAdminCpiBuilder<'a, 'b> { new_admin: self.instruction.new_admin.expect("new_admin is not set"), - restaking_program_id: self + restaking_program: self .instruction - .restaking_program_id - .expect("restaking_program_id is not set"), + .restaking_program + .expect("restaking_program is not set"), __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -465,7 +465,7 @@ struct SetNewAdminCpiBuilderInstruction<'a, 'b> { ncn: Option<&'b solana_program::account_info::AccountInfo<'a>>, ncn_admin: Option<&'b solana_program::account_info::AccountInfo<'a>>, new_admin: Option<&'b solana_program::account_info::AccountInfo<'a>>, - restaking_program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, + restaking_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, role: Option, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<( diff --git a/core/src/instruction.rs b/core/src/instruction.rs index df12d59..5e9a6d6 100644 --- a/core/src/instruction.rs +++ b/core/src/instruction.rs @@ -20,7 +20,7 @@ pub enum TipRouterInstruction { #[account(3, signer, name = "ncn_admin")] #[account(4, name = "fee_wallet")] #[account(5, name = "tie_breaker_admin")] - #[account(6, name = "restaking_program_id")] + #[account(6, name = "restaking_program")] #[account(7, name = "system_program")] InitializeNCNConfig { dao_fee_bps: u64, @@ -33,7 +33,7 @@ pub enum TipRouterInstruction { #[account(1, writable, name = "config")] #[account(2, name = "ncn")] #[account(3, signer, name = "ncn_admin")] - #[account(4, name = "restaking_program_id")] + #[account(4, name = "restaking_program")] SetConfigFees { new_dao_fee_bps: Option, new_ncn_fee_bps: Option, @@ -46,7 +46,7 @@ pub enum TipRouterInstruction { #[account(1, name = "ncn")] #[account(2, signer, name = "ncn_admin")] #[account(3, name = "new_admin")] - #[account(4, name = "restaking_program_id")] + #[account(4, name = "restaking_program")] SetNewAdmin { role: ConfigAdminRole, }, @@ -57,7 +57,7 @@ pub enum TipRouterInstruction { #[account(2, name = "ncn")] #[account(3, writable, name = "weight_table")] #[account(4, writable, signer, name = "payer")] - #[account(5, name = "restaking_program_id")] + #[account(5, name = "restaking_program")] #[account(6, name = "system_program")] InitializeWeightTable{ first_slot_of_ncn_epoch: Option, @@ -68,7 +68,7 @@ pub enum TipRouterInstruction { #[account(1, writable, name = "weight_table")] #[account(2, signer, name = "weight_table_admin")] #[account(3, name = "mint")] - #[account(4, name = "restaking_program_id")] + #[account(4, name = "restaking_program")] AdminUpdateWeightTable{ ncn_epoch: u64, weight: u128, @@ -81,7 +81,7 @@ pub enum TipRouterInstruction { #[account(3, name = "weight_table")] #[account(4, writable, name = "epoch_snapshot")] #[account(5, writable, signer, name = "payer")] - #[account(6, name = "restaking_program_id")] + #[account(6, name = "restaking_program")] #[account(7, name = "system_program")] InitializeEpochSnapshot{ first_slot_of_ncn_epoch: Option, @@ -96,7 +96,7 @@ pub enum TipRouterInstruction { #[account(5, writable, name = "epoch_snapshot")] #[account(6, writable, name = "operator_snapshot")] #[account(7, writable, signer, name = "payer")] - #[account(8, name = "restaking_program_id")] + #[account(8, name = "restaking_program")] #[account(9, name = "system_program")] InitializeOperatorSnapshot{ first_slot_of_ncn_epoch: Option, @@ -116,8 +116,9 @@ pub enum TipRouterInstruction { #[account(10, writable, name = "operator_snapshot")] #[account(11, writable, name = "vault_operator_delegation_snapshot")] #[account(12, writable, signer, name = "payer")] - #[account(13, name = "restaking_program_id")] - #[account(14, name = "system_program")] + #[account(13, name = "vault_program")] + #[account(14, name = "restaking_program")] + #[account(15, name = "system_program")] InitializeVaultOperatorDelegationSnapshot{ first_slot_of_ncn_epoch: Option, }, diff --git a/idl/jito_tip_router.json b/idl/jito_tip_router.json index 62150a7..7e5c046 100644 --- a/idl/jito_tip_router.json +++ b/idl/jito_tip_router.json @@ -36,7 +36,7 @@ "isSigner": false }, { - "name": "restakingProgramId", + "name": "restakingProgram", "isMut": false, "isSigner": false }, @@ -89,7 +89,7 @@ "isSigner": true }, { - "name": "restakingProgramId", + "name": "restakingProgram", "isMut": false, "isSigner": false } @@ -149,7 +149,7 @@ "isSigner": false }, { - "name": "restakingProgramId", + "name": "restakingProgram", "isMut": false, "isSigner": false } @@ -196,7 +196,7 @@ "isSigner": true }, { - "name": "restakingProgramId", + "name": "restakingProgram", "isMut": false, "isSigner": false }, @@ -243,7 +243,7 @@ "isSigner": false }, { - "name": "restakingProgramId", + "name": "restakingProgram", "isMut": false, "isSigner": false } @@ -297,7 +297,7 @@ "isSigner": true }, { - "name": "restakingProgramId", + "name": "restakingProgram", "isMut": false, "isSigner": false }, @@ -364,7 +364,7 @@ "isSigner": true }, { - "name": "restakingProgramId", + "name": "restakingProgram", "isMut": false, "isSigner": false }, @@ -456,7 +456,12 @@ "isSigner": true }, { - "name": "restakingProgramId", + "name": "vaultProgram", + "isMut": false, + "isSigner": false + }, + { + "name": "restakingProgram", "isMut": false, "isSigner": false }, diff --git a/integration_tests/tests/fixtures/tip_router_client.rs b/integration_tests/tests/fixtures/tip_router_client.rs index ec3a09d..3eb0d6b 100644 --- a/integration_tests/tests/fixtures/tip_router_client.rs +++ b/integration_tests/tests/fixtures/tip_router_client.rs @@ -1,16 +1,24 @@ use jito_bytemuck::AccountDeserialize; -use jito_restaking_core::config::Config; +use jito_restaking_core::{ + config::Config, ncn_operator_state::NcnOperatorState, ncn_vault_ticket::NcnVaultTicket, +}; use jito_tip_router_client::{ instructions::{ AdminUpdateWeightTableBuilder, InitializeEpochSnapshotBuilder, InitializeNCNConfigBuilder, + InitializeOperatorSnapshotBuilder, InitializeVaultOperatorDelegationSnapshotBuilder, InitializeWeightTableBuilder, SetConfigFeesBuilder, SetNewAdminBuilder, }, types::ConfigAdminRole, }; use jito_tip_router_core::{ - epoch_snapshot::EpochSnapshot, error::TipRouterError, ncn_config::NcnConfig, + epoch_snapshot::{EpochSnapshot, OperatorSnapshot, VaultOperatorDelegationSnapshot}, + error::TipRouterError, + ncn_config::NcnConfig, weight_table::WeightTable, }; +use jito_vault_core::{ + vault_ncn_ticket::VaultNcnTicket, vault_operator_delegation::VaultOperatorDelegation, +}; use solana_program::{ instruction::InstructionError, native_token::sol_to_lamports, pubkey::Pubkey, system_instruction::transfer, @@ -114,7 +122,7 @@ impl TipRouterClient { .ncn_admin(ncn_admin.pubkey()) .fee_wallet(fee_wallet) .tie_breaker_admin(tie_breaker_admin) - .restaking_program_id(jito_restaking_program::id()) + .restaking_program(jito_restaking_program::id()) .dao_fee_bps(dao_fee_bps) .ncn_fee_bps(ncn_fee_bps) .block_engine_fee_bps(block_engine_fee_bps) @@ -168,7 +176,7 @@ impl TipRouterClient { .config(config_pda) .ncn(ncn_root.ncn_pubkey) .ncn_admin(ncn_root.ncn_admin.pubkey()) - .restaking_program_id(jito_restaking_program::id()) + .restaking_program(jito_restaking_program::id()) .new_dao_fee_bps(dao_fee_bps) .new_ncn_fee_bps(ncn_fee_bps) .new_block_engine_fee_bps(block_engine_fee_bps) @@ -210,7 +218,7 @@ impl TipRouterClient { .ncn(ncn_root.ncn_pubkey) .ncn_admin(ncn_root.ncn_admin.pubkey()) .new_admin(new_admin) - .restaking_program_id(jito_restaking_program::id()) + .restaking_program(jito_restaking_program::id()) .role(role) .instruction(); @@ -252,7 +260,7 @@ impl TipRouterClient { .ncn(ncn) .weight_table(weight_table) .payer(self.payer.pubkey()) - .restaking_program_id(jito_restaking_program::id()) + .restaking_program(jito_restaking_program::id()) .system_program(system_program::id()) .instruction(); @@ -295,7 +303,7 @@ impl TipRouterClient { .weight_table(weight_table) .weight_table_admin(self.payer.pubkey()) .mint(mint) - .restaking_program_id(jito_restaking_program::id()) + .restaking_program(jito_restaking_program::id()) .weight(weight) .instruction(); @@ -309,40 +317,186 @@ impl TipRouterClient { .await } - pub async fn do_initialize_epoch_snapshot( + pub async fn do_initialize_epoch_snapshot(&mut self, ncn: Pubkey, slot: u64) -> TestResult<()> { + self.initialize_epoch_snapshot(ncn, slot).await + } + + pub async fn initialize_epoch_snapshot(&mut self, ncn: Pubkey, slot: u64) -> TestResult<()> { + let restaking_config = Config::find_program_address(&jito_restaking_program::id()).0; + + let restaking_config_account = self.get_restaking_config().await?; + let ncn_epoch = slot / restaking_config_account.epoch_length(); + + let config_pda = NcnConfig::find_program_address(&jito_tip_router_program::id(), &ncn).0; + let weight_table = + WeightTable::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; + + let epoch_snapshot = + EpochSnapshot::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; + + let ix = InitializeEpochSnapshotBuilder::new() + .ncn_config(config_pda) + .restaking_config(restaking_config) + .ncn(ncn) + .weight_table(weight_table) + .epoch_snapshot(epoch_snapshot) + .payer(self.payer.pubkey()) + .restaking_program(jito_restaking_program::id()) + .system_program(system_program::id()) + .first_slot_of_ncn_epoch(slot) + .instruction(); + + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.process_transaction(&Transaction::new_signed_with_payer( + &[ix], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + )) + .await + } + + pub async fn do_initalize_operator_snapshot( &mut self, + operator: Pubkey, ncn: Pubkey, - current_slot: u64, + slot: u64, ) -> TestResult<()> { - self.initialize_epoch_snapshot(ncn, current_slot).await + self.initalize_operator_snapshot(operator, ncn, slot).await } - pub async fn initialize_epoch_snapshot( + pub async fn initalize_operator_snapshot( &mut self, + operator: Pubkey, ncn: Pubkey, - current_slot: u64, + slot: u64, ) -> TestResult<()> { let restaking_config = Config::find_program_address(&jito_restaking_program::id()).0; let restaking_config_account = self.get_restaking_config().await?; - let ncn_epoch = current_slot / restaking_config_account.epoch_length(); + let ncn_epoch = slot / restaking_config_account.epoch_length(); let config_pda = NcnConfig::find_program_address(&jito_tip_router_program::id(), &ncn).0; - let weight_table = - WeightTable::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; let epoch_snapshot = EpochSnapshot::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; - let ix = InitializeEpochSnapshotBuilder::new() + let ncn_operator_state = + NcnOperatorState::find_program_address(&jito_restaking_program::id(), &ncn, &operator) + .0; + + let operator_snapshot = OperatorSnapshot::find_program_address( + &jito_tip_router_program::id(), + &operator, + &ncn, + ncn_epoch, + ) + .0; + + let ix = InitializeOperatorSnapshotBuilder::new() + .ncn_config(config_pda) .restaking_config(restaking_config) + .ncn(ncn) + .operator(operator) + .ncn_operator_state(ncn_operator_state) + .epoch_snapshot(epoch_snapshot) + .operator_snapshot(operator_snapshot) + .payer(self.payer.pubkey()) + .restaking_program(jito_restaking_program::id()) + .system_program(system_program::id()) + .first_slot_of_ncn_epoch(slot) + .instruction(); + + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.process_transaction(&Transaction::new_signed_with_payer( + &[ix], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + )) + .await + } + + pub async fn do_initalize_vault_operator_delegation_snapshot( + &mut self, + vault: Pubkey, + operator: Pubkey, + ncn: Pubkey, + slot: u64, + ) -> TestResult<()> { + self.initalize_vault_operator_delegation_snapshot(vault, operator, ncn, slot) + .await + } + + pub async fn initalize_vault_operator_delegation_snapshot( + &mut self, + vault: Pubkey, + operator: Pubkey, + ncn: Pubkey, + slot: u64, + ) -> TestResult<()> { + let restaking_config = Config::find_program_address(&jito_restaking_program::id()).0; + + let restaking_config_account = self.get_restaking_config().await?; + let ncn_epoch = slot / restaking_config_account.epoch_length(); + + let config_pda = NcnConfig::find_program_address(&jito_tip_router_program::id(), &ncn).0; + + let epoch_snapshot = + EpochSnapshot::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; + + let operator_snapshot = OperatorSnapshot::find_program_address( + &jito_tip_router_program::id(), + &operator, + &ncn, + ncn_epoch, + ) + .0; + + let vault_ncn_ticket = + VaultNcnTicket::find_program_address(&jito_vault_program::id(), &vault, &ncn).0; + + let ncn_vault_ticket = + NcnVaultTicket::find_program_address(&jito_restaking_program::id(), &ncn, &vault).0; + + let vault_operator_delegation = VaultOperatorDelegation::find_program_address( + &jito_vault_program::id(), + &vault, + &operator, + ) + .0; + + let weight_table = + WeightTable::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; + + let vault_operator_delegation_snapshot = + VaultOperatorDelegationSnapshot::find_program_address( + &jito_tip_router_program::id(), + &vault, + &operator, + &ncn, + ncn_epoch, + ) + .0; + + let ix = InitializeVaultOperatorDelegationSnapshotBuilder::new() .ncn_config(config_pda) + .restaking_config(restaking_config) .ncn(ncn) + .operator(operator) + .vault(vault) + .vault_ncn_ticket(vault_ncn_ticket) + .ncn_vault_ticket(ncn_vault_ticket) + .vault_operator_delegation(vault_operator_delegation) .weight_table(weight_table) .epoch_snapshot(epoch_snapshot) + .operator_snapshot(operator_snapshot) + .vault_operator_delegation_snapshot(vault_operator_delegation_snapshot) .payer(self.payer.pubkey()) - .restaking_program_id(jito_restaking_program::id()) + .vault_program(jito_vault_program::id()) + .restaking_program(jito_restaking_program::id()) .system_program(system_program::id()) + .first_slot_of_ncn_epoch(slot) .instruction(); let blockhash = self.banks_client.get_latest_blockhash().await?; diff --git a/program/Cargo.toml b/program/Cargo.toml index a7819c4..78f6afb 100644 --- a/program/Cargo.toml +++ b/program/Cargo.toml @@ -36,6 +36,7 @@ jito-restaking-program = { workspace = true } jito-restaking-sdk = { workspace = true } jito-tip-router-core = { workspace = true } jito-vault-core = { workspace = true } +jito-vault-program = { workspace = true } jito-vault-sdk = { workspace = true } shank = { workspace = true } solana-program = { workspace = true } diff --git a/program/src/admin_update_weight_table.rs b/program/src/admin_update_weight_table.rs index ea52234..c27ddf5 100644 --- a/program/src/admin_update_weight_table.rs +++ b/program/src/admin_update_weight_table.rs @@ -14,11 +14,11 @@ pub fn process_admin_update_weight_table( ncn_epoch: u64, weight: u128, ) -> ProgramResult { - let [ncn, weight_table, weight_table_admin, mint, restaking_program_id] = accounts else { + let [ncn, weight_table, weight_table_admin, mint, restaking_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - Ncn::load(restaking_program_id.key, ncn, false)?; + Ncn::load(restaking_program.key, ncn, false)?; let ncn_weight_table_admin = { let ncn_data = ncn.data.borrow(); let ncn = Ncn::try_from_slice_unchecked(&ncn_data)?; @@ -29,7 +29,7 @@ pub fn process_admin_update_weight_table( load_token_mint(mint)?; WeightTable::load(program_id, weight_table, ncn, ncn_epoch, true)?; - if restaking_program_id.key.ne(&jito_restaking_program::id()) { + if restaking_program.key.ne(&jito_restaking_program::id()) { msg!("Incorrect restaking program ID"); return Err(ProgramError::InvalidAccountData); } diff --git a/program/src/initialize_epoch_snapshot.rs b/program/src/initialize_epoch_snapshot.rs index 92c2bb4..8ae74a1 100644 --- a/program/src/initialize_epoch_snapshot.rs +++ b/program/src/initialize_epoch_snapshot.rs @@ -19,20 +19,20 @@ pub fn process_initialize_epoch_snapshot( accounts: &[AccountInfo], first_slot_of_ncn_epoch: Option, ) -> ProgramResult { - let [ncn_config, restaking_config, ncn, weight_table, epoch_snapshot, payer, restaking_program_id, system_program] = + let [ncn_config, restaking_config, ncn, weight_table, epoch_snapshot, payer, restaking_program, system_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - if restaking_program_id.key.ne(&jito_restaking_program::id()) { + if restaking_program.key.ne(&jito_restaking_program::id()) { msg!("Incorrect restaking program ID"); return Err(ProgramError::InvalidAccountData); } NcnConfig::load(program_id, ncn.key, ncn_config, false)?; - Config::load(restaking_program_id.key, restaking_config, false)?; - Ncn::load(restaking_program_id.key, ncn, false)?; + Config::load(restaking_program.key, restaking_config, false)?; + Ncn::load(restaking_program.key, ncn, false)?; load_system_account(epoch_snapshot, true)?; load_system_program(system_program)?; diff --git a/program/src/initialize_ncn_config.rs b/program/src/initialize_ncn_config.rs index 3d4cad2..83b450e 100644 --- a/program/src/initialize_ncn_config.rs +++ b/program/src/initialize_ncn_config.rs @@ -19,7 +19,7 @@ pub fn process_initialize_ncn_config( ncn_fee_bps: u64, block_engine_fee_bps: u64, ) -> ProgramResult { - let [restaking_config, ncn_config, ncn_account, fee_wallet, ncn_admin, tie_breaker_admin, restaking_program_id, system_program] = + let [restaking_config, ncn_config, ncn_account, fee_wallet, ncn_admin, tie_breaker_admin, restaking_program, system_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -29,8 +29,8 @@ pub fn process_initialize_ncn_config( load_system_program(system_program)?; load_signer(ncn_admin, false)?; - Ncn::load(restaking_program_id.key, ncn_account, false)?; - Config::load(restaking_program_id.key, restaking_config, false)?; + Ncn::load(restaking_program.key, ncn_account, false)?; + Config::load(restaking_program.key, restaking_config, false)?; let ncn_epoch_length = { let config_data = restaking_config.data.borrow(); diff --git a/program/src/initialize_operator_snapshot.rs b/program/src/initialize_operator_snapshot.rs index dbc6726..75ff1ac 100644 --- a/program/src/initialize_operator_snapshot.rs +++ b/program/src/initialize_operator_snapshot.rs @@ -22,23 +22,23 @@ pub fn process_initialize_operator_snapshot( accounts: &[AccountInfo], first_slot_of_ncn_epoch: Option, ) -> ProgramResult { - let [ncn_config, restaking_config, ncn, operator, ncn_operator_state, epoch_snapshot, operator_snapshot, payer, restaking_program_id, system_program] = + let [ncn_config, restaking_config, ncn, operator, ncn_operator_state, epoch_snapshot, operator_snapshot, payer, restaking_program, system_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - if restaking_program_id.key.ne(&jito_restaking_program::id()) { + if restaking_program.key.ne(&jito_restaking_program::id()) { msg!("Incorrect restaking program ID"); return Err(ProgramError::InvalidAccountData); } NcnConfig::load(program_id, ncn.key, ncn_config, false)?; - Config::load(restaking_program_id.key, restaking_config, false)?; - Ncn::load(restaking_program_id.key, ncn, false)?; - Operator::load(restaking_program_id.key, operator, false)?; + Config::load(restaking_program.key, restaking_config, false)?; + Ncn::load(restaking_program.key, ncn, false)?; + Operator::load(restaking_program.key, operator, false)?; NcnOperatorState::load( - restaking_program_id.key, + restaking_program.key, ncn_operator_state, ncn, operator, diff --git a/program/src/initialize_vault_operator_delegation_snapshot.rs b/program/src/initialize_vault_operator_delegation_snapshot.rs index 12b9f4a..147095e 100644 --- a/program/src/initialize_vault_operator_delegation_snapshot.rs +++ b/program/src/initialize_vault_operator_delegation_snapshot.rs @@ -26,43 +26,44 @@ pub fn process_initialize_vault_operator_delegation_snapshot( accounts: &[AccountInfo], first_slot_of_ncn_epoch: Option, ) -> ProgramResult { - let [ncn_config, restaking_config, ncn, operator, vault, vault_ncn_ticket, ncn_vault_ticket, vault_operator_delegation, weight_table, epoch_snapshot, operator_snapshot, vault_operator_delegation_snapshot, payer, restaking_program_id, system_program] = + let [ncn_config, restaking_config, ncn, operator, vault, vault_ncn_ticket, ncn_vault_ticket, vault_operator_delegation, weight_table, epoch_snapshot, operator_snapshot, vault_operator_delegation_snapshot, payer, vault_program, restaking_program, system_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - if restaking_program_id.key.ne(&jito_restaking_program::id()) { + if vault_program.key.ne(&jito_vault_program::id()) { + msg!("Incorrect vault program ID"); + return Err(ProgramError::InvalidAccountData); + } + + if restaking_program.key.ne(&jito_restaking_program::id()) { msg!("Incorrect restaking program ID"); return Err(ProgramError::InvalidAccountData); } NcnConfig::load(program_id, ncn.key, ncn_config, false)?; - Config::load(restaking_program_id.key, restaking_config, false)?; - Ncn::load(restaking_program_id.key, ncn, false)?; - Operator::load(restaking_program_id.key, operator, false)?; - Vault::load(restaking_program_id.key, vault, false)?; - - VaultNcnTicket::load( - restaking_program_id.key, - vault_ncn_ticket, - vault, - ncn, - false, - )?; - NcnVaultTicket::load( - restaking_program_id.key, - ncn_vault_ticket, - ncn, + Config::load(restaking_program.key, restaking_config, false)?; + Ncn::load(restaking_program.key, ncn, false)?; + Operator::load(restaking_program.key, operator, false)?; + Vault::load(vault_program.key, vault, false)?; + + VaultOperatorDelegation::load( + vault_program.key, + vault_operator_delegation, vault, + operator, false, )?; + VaultNcnTicket::load(vault_program.key, vault_ncn_ticket, vault, ncn, false)?; + NcnVaultTicket::load(restaking_program.key, ncn_vault_ticket, ncn, vault, false)?; //TODO check that st mint is supported? //TODO may not exist + //TODO what happens if a new Vault is added inbetween weight table creation and this? - There could be a count mismatch if !vault_operator_delegation.data_is_empty() { VaultOperatorDelegation::load( - restaking_program_id.key, + restaking_program.key, vault_operator_delegation, vault, operator, diff --git a/program/src/initialize_weight_table.rs b/program/src/initialize_weight_table.rs index 384a8be..538ceba 100644 --- a/program/src/initialize_weight_table.rs +++ b/program/src/initialize_weight_table.rs @@ -21,20 +21,20 @@ pub fn process_initialize_weight_table( accounts: &[AccountInfo], first_slot_of_ncn_epoch: Option, ) -> ProgramResult { - let [restaking_config, ncn_config, ncn, weight_table, payer, restaking_program_id, system_program] = + let [restaking_config, ncn_config, ncn, weight_table, payer, restaking_program, system_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; - if restaking_program_id.key.ne(&jito_restaking_program::id()) { + if restaking_program.key.ne(&jito_restaking_program::id()) { msg!("Incorrect restaking program ID"); return Err(ProgramError::InvalidAccountData); } NcnConfig::load(program_id, ncn.key, ncn_config, false)?; - Config::load(restaking_program_id.key, restaking_config, false)?; - Ncn::load(restaking_program_id.key, ncn, false)?; + Config::load(restaking_program.key, restaking_config, false)?; + Ncn::load(restaking_program.key, ncn, false)?; load_system_account(weight_table, true)?; load_system_program(system_program)?; diff --git a/program/src/set_config_fees.rs b/program/src/set_config_fees.rs index 0a25946..7df9a95 100644 --- a/program/src/set_config_fees.rs +++ b/program/src/set_config_fees.rs @@ -15,15 +15,15 @@ pub fn process_set_config_fees( new_block_engine_fee_bps: Option, new_fee_wallet: Option, ) -> ProgramResult { - let [restaking_config, config, ncn_account, fee_admin, restaking_program_id] = accounts else { + let [restaking_config, config, ncn_account, fee_admin, restaking_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; load_signer(fee_admin, true)?; NcnConfig::load(program_id, ncn_account.key, config, true)?; - Ncn::load(restaking_program_id.key, ncn_account, false)?; - Config::load(restaking_program_id.key, restaking_config, false)?; + Ncn::load(restaking_program.key, ncn_account, false)?; + Config::load(restaking_program.key, restaking_config, false)?; let ncn_epoch_length = { let config_data = restaking_config.data.borrow(); diff --git a/program/src/set_new_admin.rs b/program/src/set_new_admin.rs index 1e1f09f..578bcc2 100644 --- a/program/src/set_new_admin.rs +++ b/program/src/set_new_admin.rs @@ -14,14 +14,14 @@ pub fn process_set_new_admin( accounts: &[AccountInfo], role: ConfigAdminRole, ) -> ProgramResult { - let [config, ncn_account, ncn_admin, new_admin, restaking_program_id] = accounts else { + let [config, ncn_account, ncn_admin, new_admin, restaking_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); }; load_signer(ncn_admin, true)?; NcnConfig::load(program_id, ncn_account.key, config, true)?; - Ncn::load(restaking_program_id.key, ncn_account, false)?; + Ncn::load(restaking_program.key, ncn_account, false)?; let mut config_data = config.try_borrow_mut_data()?; if config_data[0] != NcnConfig::DISCRIMINATOR { From a4f17b6976783c5a6c204e52f3bef3040be3fc22 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Tue, 12 Nov 2024 15:32:42 -0800 Subject: [PATCH 09/28] testing setup closer --- core/src/epoch_snapshot.rs | 2 +- integration_tests/tests/fixtures/mod.rs | 1 + .../tests/fixtures/restaking_client.rs | 1003 +++++++++- .../tests/fixtures/test_builder.rs | 178 +- .../tests/fixtures/vault_client.rs | 1650 ++++++++++++++++- 5 files changed, 2796 insertions(+), 38 deletions(-) diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index d5d934f..8815e18 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -270,7 +270,7 @@ impl OperatorSnapshot { bump: u8, current_slot: u64, ) -> Self { - let mut snapshot = Self::new(operator, ncn, ncn_epoch, bump, current_slot, true, 0, 0); + let mut snapshot = Self::new(operator, ncn, ncn_epoch, bump, current_slot, false, 0, 0); snapshot.slot_finalized = PodU64::from(current_slot); snapshot diff --git a/integration_tests/tests/fixtures/mod.rs b/integration_tests/tests/fixtures/mod.rs index c15b19b..cfc6717 100644 --- a/integration_tests/tests/fixtures/mod.rs +++ b/integration_tests/tests/fixtures/mod.rs @@ -6,6 +6,7 @@ use thiserror::Error; pub mod restaking_client; pub mod test_builder; pub mod tip_router_client; +pub mod vault_client; pub type TestResult = Result; diff --git a/integration_tests/tests/fixtures/restaking_client.rs b/integration_tests/tests/fixtures/restaking_client.rs index 9128bf8..ab0d6b1 100644 --- a/integration_tests/tests/fixtures/restaking_client.rs +++ b/integration_tests/tests/fixtures/restaking_client.rs @@ -1,12 +1,34 @@ -use jito_restaking_core::{config::Config, ncn::Ncn}; -use jito_restaking_sdk::sdk::{initialize_config, initialize_ncn}; +use jito_bytemuck::AccountDeserialize; +use jito_restaking_core::{ + config::Config, ncn::Ncn, ncn_operator_state::NcnOperatorState, + ncn_vault_slasher_ticket::NcnVaultSlasherTicket, ncn_vault_ticket::NcnVaultTicket, + operator::Operator, operator_vault_ticket::OperatorVaultTicket, +}; +use jito_restaking_sdk::{ + error::RestakingError, + instruction::OperatorAdminRole, + sdk::{ + cooldown_ncn_vault_ticket, initialize_config, initialize_ncn, + initialize_ncn_operator_state, initialize_ncn_vault_slasher_ticket, + initialize_ncn_vault_ticket, initialize_operator, initialize_operator_vault_ticket, + ncn_cooldown_operator, ncn_set_admin, ncn_warmup_operator, operator_cooldown_ncn, + operator_set_admin, operator_set_fee, operator_set_secondary_admin, operator_warmup_ncn, + set_config_admin, warmup_ncn_vault_slasher_ticket, warmup_ncn_vault_ticket, + warmup_operator_vault_ticket, + }, +}; +use solana_program::{ + instruction::InstructionError, native_token::sol_to_lamports, pubkey::Pubkey, + system_instruction::transfer, +}; use solana_program_test::BanksClient; use solana_sdk::{ - commitment_config::CommitmentLevel, native_token::sol_to_lamports, pubkey::Pubkey, - signature::Keypair, signer::Signer, system_instruction::transfer, transaction::Transaction, + commitment_config::CommitmentLevel, + signature::{Keypair, Signer}, + transaction::{Transaction, TransactionError}, }; -use super::TestResult; +use crate::fixtures::{TestError, TestResult}; #[derive(Debug)] pub struct NcnRoot { @@ -14,6 +36,12 @@ pub struct NcnRoot { pub ncn_admin: Keypair, } +#[derive(Debug)] +pub struct OperatorRoot { + pub operator_pubkey: Pubkey, + pub operator_admin: Keypair, +} + pub struct RestakingProgramClient { banks_client: BanksClient, payer: Keypair, @@ -27,43 +55,189 @@ impl RestakingProgramClient { } } - pub async fn process_transaction(&mut self, tx: &Transaction) -> TestResult<()> { - self.banks_client - .process_transaction_with_preflight_and_commitment( - tx.clone(), - CommitmentLevel::Processed, - ) - .await?; - Ok(()) + pub async fn get_ncn(&mut self, ncn: &Pubkey) -> TestResult { + let account = self + .banks_client + .get_account_with_commitment(*ncn, CommitmentLevel::Processed) + .await? + .unwrap(); + + Ok(*Ncn::try_from_slice_unchecked(account.data.as_slice())?) } - pub async fn airdrop(&mut self, to: &Pubkey, sol: f64) -> TestResult<()> { - let blockhash = self.banks_client.get_latest_blockhash().await?; - self.banks_client - .process_transaction_with_preflight_and_commitment( - Transaction::new_signed_with_payer( - &[transfer(&self.payer.pubkey(), to, sol_to_lamports(sol))], - Some(&self.payer.pubkey()), - &[&self.payer], - blockhash, - ), - CommitmentLevel::Processed, - ) - .await?; - Ok(()) + pub async fn get_config(&mut self, account: &Pubkey) -> TestResult { + let account = self.banks_client.get_account(*account).await?.unwrap(); + Ok(*Config::try_from_slice_unchecked(account.data.as_slice())?) + } + + pub async fn get_ncn_vault_ticket( + &mut self, + ncn: &Pubkey, + vault: &Pubkey, + ) -> TestResult { + let account = + NcnVaultTicket::find_program_address(&jito_restaking_program::id(), ncn, vault).0; + let account = self.banks_client.get_account(account).await?.unwrap(); + Ok(*NcnVaultTicket::try_from_slice_unchecked( + account.data.as_slice(), + )?) + } + + pub async fn get_ncn_operator_state( + &mut self, + ncn: &Pubkey, + operator: &Pubkey, + ) -> TestResult { + let account = + NcnOperatorState::find_program_address(&jito_restaking_program::id(), ncn, operator).0; + let account = self.banks_client.get_account(account).await?.unwrap(); + Ok(*NcnOperatorState::try_from_slice_unchecked( + account.data.as_slice(), + )?) + } + + pub async fn get_operator(&mut self, account: &Pubkey) -> TestResult { + let account = self.banks_client.get_account(*account).await?.unwrap(); + Ok(*Operator::try_from_slice_unchecked( + account.data.as_slice(), + )?) + } + + pub async fn get_operator_vault_ticket( + &mut self, + operator: &Pubkey, + vault: &Pubkey, + ) -> TestResult { + let account = OperatorVaultTicket::find_program_address( + &jito_restaking_program::id(), + operator, + vault, + ) + .0; + let account = self.banks_client.get_account(account).await?.unwrap(); + Ok(*OperatorVaultTicket::try_from_slice_unchecked( + account.data.as_slice(), + )?) + } + + #[allow(dead_code)] + pub async fn get_operator_ncn_ticket( + &mut self, + operator: &Pubkey, + ncn: &Pubkey, + ) -> TestResult { + let account = + NcnOperatorState::find_program_address(&jito_restaking_program::id(), operator, ncn).0; + let account = self.banks_client.get_account(account).await?.unwrap(); + Ok(*NcnOperatorState::try_from_slice_unchecked( + account.data.as_slice(), + )?) } pub async fn do_initialize_config(&mut self) -> TestResult { let restaking_config_pubkey = Config::find_program_address(&jito_restaking_program::id()).0; let restaking_config_admin = Keypair::new(); - self.airdrop(&restaking_config_admin.pubkey(), 10.0).await?; + self.airdrop(&restaking_config_admin.pubkey(), 1.0).await?; self.initialize_config(&restaking_config_pubkey, &restaking_config_admin) .await?; Ok(restaking_config_admin) } + pub async fn do_initialize_operator(&mut self) -> TestResult { + // create operator + add operator vault + let operator_base = Keypair::new(); + let operator_pubkey = + Operator::find_program_address(&jito_restaking_program::id(), &operator_base.pubkey()) + .0; + let operator_admin = Keypair::new(); + self.airdrop(&operator_admin.pubkey(), 1.0).await?; + self.initialize_operator( + &Config::find_program_address(&jito_restaking_program::id()).0, + &operator_pubkey, + &operator_admin, + &operator_base, + 0, + ) + .await?; + Ok(OperatorRoot { + operator_pubkey, + operator_admin, + }) + } + + pub async fn do_initialize_operator_vault_ticket( + &mut self, + operator_root: &OperatorRoot, + vault_pubkey: &Pubkey, + ) -> TestResult<()> { + let operator_vault_ticket = OperatorVaultTicket::find_program_address( + &jito_restaking_program::id(), + &operator_root.operator_pubkey, + vault_pubkey, + ) + .0; + self.initialize_operator_vault_ticket( + &Config::find_program_address(&jito_restaking_program::id()).0, + &operator_root.operator_pubkey, + vault_pubkey, + &operator_vault_ticket, + &operator_root.operator_admin, + &operator_root.operator_admin, + ) + .await?; + + Ok(()) + } + + pub async fn do_warmup_operator_vault_ticket( + &mut self, + operator_root: &OperatorRoot, + vault_pubkey: &Pubkey, + ) -> TestResult<()> { + let operator_vault_ticket = OperatorVaultTicket::find_program_address( + &jito_restaking_program::id(), + &operator_root.operator_pubkey, + vault_pubkey, + ) + .0; + self.warmup_operator_vault_ticket( + &Config::find_program_address(&jito_restaking_program::id()).0, + &operator_root.operator_pubkey, + vault_pubkey, + &operator_vault_ticket, + &operator_root.operator_admin, + ) + .await + } + + pub async fn warmup_operator_vault_ticket( + &mut self, + config: &Pubkey, + operator: &Pubkey, + vault: &Pubkey, + operator_vault_ticket: &Pubkey, + admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[warmup_operator_vault_ticket( + &jito_restaking_program::id(), + config, + operator, + vault, + operator_vault_ticket, + &admin.pubkey(), + )], + Some(&self.payer.pubkey()), + &[admin, &self.payer], + blockhash, + )) + .await + } + pub async fn initialize_config( &mut self, config: &Pubkey, @@ -106,6 +280,429 @@ impl RestakingProgramClient { }) } + pub async fn do_initialize_ncn_vault_ticket( + &mut self, + ncn_root: &NcnRoot, + vault: &Pubkey, + ) -> TestResult<()> { + let ncn_vault_ticket = NcnVaultTicket::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + vault, + ) + .0; + + self.initialize_ncn_vault_ticket( + &Config::find_program_address(&jito_restaking_program::id()).0, + &ncn_root.ncn_pubkey, + vault, + &ncn_vault_ticket, + &ncn_root.ncn_admin, + &self.payer.insecure_clone(), + ) + .await + } + + pub async fn do_warmup_ncn_vault_ticket( + &mut self, + ncn_root: &NcnRoot, + vault: &Pubkey, + ) -> TestResult<()> { + let ncn_vault_ticket = NcnVaultTicket::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + vault, + ) + .0; + self.warmup_ncn_vault_ticket( + &Config::find_program_address(&jito_restaking_program::id()).0, + &ncn_root.ncn_pubkey, + vault, + &ncn_vault_ticket, + &ncn_root.ncn_admin, + ) + .await + } + + pub async fn warmup_ncn_vault_ticket( + &mut self, + config: &Pubkey, + ncn: &Pubkey, + vault: &Pubkey, + ncn_vault_ticket: &Pubkey, + admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[warmup_ncn_vault_ticket( + &jito_restaking_program::id(), + config, + ncn, + vault, + ncn_vault_ticket, + &admin.pubkey(), + )], + Some(&self.payer.pubkey()), + &[admin, &self.payer], + blockhash, + )) + .await + } + + #[allow(dead_code)] + pub async fn do_cooldown_ncn_vault_ticket( + &mut self, + ncn_root: &NcnRoot, + vault: &Pubkey, + ) -> TestResult<()> { + let ncn_vault_ticket = NcnVaultTicket::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + vault, + ) + .0; + self.cooldown_ncn_vault_ticket( + &Config::find_program_address(&jito_restaking_program::id()).0, + &ncn_root.ncn_pubkey, + vault, + &ncn_vault_ticket, + &ncn_root.ncn_admin, + ) + .await + } + + #[allow(dead_code)] + pub async fn cooldown_ncn_vault_ticket( + &mut self, + config: &Pubkey, + ncn: &Pubkey, + vault: &Pubkey, + ncn_vault_ticket: &Pubkey, + admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[cooldown_ncn_vault_ticket( + &jito_restaking_program::id(), + config, + ncn, + vault, + ncn_vault_ticket, + &admin.pubkey(), + )], + Some(&self.payer.pubkey()), + &[admin, &self.payer], + blockhash, + )) + .await + } + + pub async fn do_ncn_warmup_operator( + &mut self, + ncn_root: &NcnRoot, + operator_pubkey: &Pubkey, + ) -> TestResult<()> { + self.ncn_warmup_operator( + &Config::find_program_address(&jito_restaking_program::id()).0, + &ncn_root.ncn_pubkey, + operator_pubkey, + &NcnOperatorState::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + operator_pubkey, + ) + .0, + &ncn_root.ncn_admin, + ) + .await + } + + pub async fn do_ncn_cooldown_operator( + &mut self, + ncn_root: &NcnRoot, + operator_pubkey: &Pubkey, + ) -> TestResult<()> { + self.ncn_cooldown_operator( + &Config::find_program_address(&jito_restaking_program::id()).0, + &ncn_root.ncn_pubkey, + operator_pubkey, + &NcnOperatorState::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + operator_pubkey, + ) + .0, + &ncn_root.ncn_admin, + ) + .await + } + + pub async fn ncn_cooldown_operator( + &mut self, + config: &Pubkey, + ncn: &Pubkey, + operator_pubkey: &Pubkey, + ncn_operator_state: &Pubkey, + admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[ncn_cooldown_operator( + &jito_restaking_program::id(), + config, + ncn, + operator_pubkey, + ncn_operator_state, + &admin.pubkey(), + )], + Some(&self.payer.pubkey()), + &[admin, &self.payer], + blockhash, + )) + .await + } + + pub async fn ncn_warmup_operator( + &mut self, + config: &Pubkey, + ncn: &Pubkey, + operator_pubkey: &Pubkey, + ncn_operator_state: &Pubkey, + admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[ncn_warmup_operator( + &jito_restaking_program::id(), + config, + ncn, + operator_pubkey, + ncn_operator_state, + &admin.pubkey(), + )], + Some(&self.payer.pubkey()), + &[admin, &self.payer], + blockhash, + )) + .await + } + + pub async fn do_operator_warmup_ncn( + &mut self, + operator_root: &OperatorRoot, + ncn_pubkey: &Pubkey, + ) -> TestResult<()> { + self.operator_warmup_ncn( + &Config::find_program_address(&jito_restaking_program::id()).0, + ncn_pubkey, + &operator_root.operator_pubkey, + &NcnOperatorState::find_program_address( + &jito_restaking_program::id(), + ncn_pubkey, + &operator_root.operator_pubkey, + ) + .0, + &operator_root.operator_admin, + ) + .await + } + + pub async fn operator_warmup_ncn( + &mut self, + config: &Pubkey, + ncn_pubkey: &Pubkey, + operator_pubkey: &Pubkey, + ncn_operator_state: &Pubkey, + admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[operator_warmup_ncn( + &jito_restaking_program::id(), + config, + ncn_pubkey, + operator_pubkey, + ncn_operator_state, + &admin.pubkey(), + )], + Some(&self.payer.pubkey()), + &[admin, &self.payer], + blockhash, + )) + .await + } + + pub async fn do_operator_cooldown_ncn( + &mut self, + operator_root: &OperatorRoot, + ncn_pubkey: &Pubkey, + ) -> TestResult<()> { + self.operator_cooldown_ncn( + &Config::find_program_address(&jito_restaking_program::id()).0, + ncn_pubkey, + &operator_root.operator_pubkey, + &NcnOperatorState::find_program_address( + &jito_restaking_program::id(), + ncn_pubkey, + &operator_root.operator_pubkey, + ) + .0, + &operator_root.operator_admin, + ) + .await + } + + pub async fn operator_cooldown_ncn( + &mut self, + config: &Pubkey, + ncn_pubkey: &Pubkey, + operator_pubkey: &Pubkey, + ncn_operator_state: &Pubkey, + admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[operator_cooldown_ncn( + &jito_restaking_program::id(), + config, + ncn_pubkey, + operator_pubkey, + ncn_operator_state, + &admin.pubkey(), + )], + Some(&self.payer.pubkey()), + &[admin, &self.payer], + blockhash, + )) + .await + } + + pub async fn do_initialize_ncn_operator_state( + &mut self, + ncn_root: &NcnRoot, + operator: &Pubkey, + ) -> TestResult<()> { + let ncn_operator_state = NcnOperatorState::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + operator, + ) + .0; + + self.initialize_ncn_operator_state( + &Config::find_program_address(&jito_restaking_program::id()).0, + &ncn_root.ncn_pubkey, + operator, + &ncn_operator_state, + &ncn_root.ncn_admin, + &self.payer.insecure_clone(), + ) + .await + } + + pub async fn do_initialize_ncn_vault_slasher_ticket( + &mut self, + ncn_root: &NcnRoot, + vault: &Pubkey, + slasher: &Pubkey, + max_slash_amount: u64, + ) -> TestResult<()> { + let ncn_vault_ticket = NcnVaultTicket::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + vault, + ) + .0; + let ncn_slasher_ticket = NcnVaultSlasherTicket::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + vault, + slasher, + ) + .0; + + self.initialize_ncn_vault_slasher_ticket( + &Config::find_program_address(&jito_restaking_program::id()).0, + &ncn_root.ncn_pubkey, + vault, + slasher, + &ncn_vault_ticket, + &ncn_slasher_ticket, + &ncn_root.ncn_admin, + &self.payer.insecure_clone(), + max_slash_amount, + ) + .await + } + + pub async fn do_warmup_ncn_vault_slasher_ticket( + &mut self, + ncn_root: &NcnRoot, + vault: &Pubkey, + slasher: &Pubkey, + ) -> TestResult<()> { + let ncn_vault_ticket = NcnVaultTicket::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + vault, + ) + .0; + let ncn_slasher_ticket = NcnVaultSlasherTicket::find_program_address( + &jito_restaking_program::id(), + &ncn_root.ncn_pubkey, + vault, + slasher, + ) + .0; + + self.warmup_ncn_vault_slasher_ticket( + &Config::find_program_address(&jito_restaking_program::id()).0, + &ncn_root.ncn_pubkey, + vault, + slasher, + &ncn_vault_ticket, + &ncn_slasher_ticket, + &ncn_root.ncn_admin, + ) + .await + } + + pub async fn warmup_ncn_vault_slasher_ticket( + &mut self, + config: &Pubkey, + ncn: &Pubkey, + vault: &Pubkey, + slasher: &Pubkey, + ncn_vault_ticket: &Pubkey, + ncn_slasher_ticket: &Pubkey, + admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[warmup_ncn_vault_slasher_ticket( + &jito_restaking_program::id(), + config, + ncn, + vault, + slasher, + ncn_vault_ticket, + ncn_slasher_ticket, + &admin.pubkey(), + )], + Some(&self.payer.pubkey()), + &[admin, &self.payer], + blockhash, + )) + .await + } + pub async fn initialize_ncn( &mut self, config: &Pubkey, @@ -129,4 +726,354 @@ impl RestakingProgramClient { )) .await } + + pub async fn initialize_ncn_vault_ticket( + &mut self, + config: &Pubkey, + ncn: &Pubkey, + vault: &Pubkey, + ncn_vault_ticket: &Pubkey, + ncn_admin: &Keypair, + payer: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[initialize_ncn_vault_ticket( + &jito_restaking_program::id(), + config, + ncn, + vault, + ncn_vault_ticket, + &ncn_admin.pubkey(), + &payer.pubkey(), + )], + Some(&payer.pubkey()), + &[ncn_admin, payer], + blockhash, + )) + .await + } + + pub async fn initialize_ncn_operator_state( + &mut self, + config: &Pubkey, + ncn: &Pubkey, + operator: &Pubkey, + ncn_operator_state: &Pubkey, + ncn_admin: &Keypair, + payer: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[initialize_ncn_operator_state( + &jito_restaking_program::id(), + config, + ncn, + operator, + ncn_operator_state, + &ncn_admin.pubkey(), + &payer.pubkey(), + )], + Some(&payer.pubkey()), + &[ncn_admin, payer], + blockhash, + )) + .await + } + + pub async fn initialize_ncn_vault_slasher_ticket( + &mut self, + config: &Pubkey, + ncn: &Pubkey, + vault: &Pubkey, + slasher: &Pubkey, + ncn_vault_ticket: &Pubkey, + ncn_slasher_ticket: &Pubkey, + ncn_admin: &Keypair, + payer: &Keypair, + max_slash_amount: u64, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[initialize_ncn_vault_slasher_ticket( + &jito_restaking_program::id(), + config, + ncn, + vault, + slasher, + ncn_vault_ticket, + ncn_slasher_ticket, + &ncn_admin.pubkey(), + &payer.pubkey(), + max_slash_amount, + )], + Some(&payer.pubkey()), + &[ncn_admin, payer], + blockhash, + )) + .await + } + + pub async fn ncn_set_admin( + &mut self, + ncn: &Pubkey, + old_admin: &Keypair, + new_admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[ncn_set_admin( + &jito_restaking_program::id(), + ncn, + &old_admin.pubkey(), + &new_admin.pubkey(), + )], + Some(&old_admin.pubkey()), + &[old_admin, new_admin], + blockhash, + )) + .await + } + + pub async fn operator_set_admin( + &mut self, + operator: &Pubkey, + old_admin: &Keypair, + new_admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[operator_set_admin( + &jito_restaking_program::id(), + operator, + &old_admin.pubkey(), + &new_admin.pubkey(), + )], + Some(&old_admin.pubkey()), + &[old_admin, new_admin], + blockhash, + )) + .await + } + + pub async fn operator_set_secondary_admin( + &mut self, + operator: &Pubkey, + old_admin: &Keypair, + new_admin: &Keypair, + operator_admin_role: OperatorAdminRole, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[operator_set_secondary_admin( + &jito_restaking_program::id(), + operator, + &old_admin.pubkey(), + &new_admin.pubkey(), + operator_admin_role, + )], + Some(&old_admin.pubkey()), + &[old_admin], + blockhash, + )) + .await + } + + pub async fn initialize_operator( + &mut self, + config: &Pubkey, + operator: &Pubkey, + admin: &Keypair, + base: &Keypair, + operator_fee_bps: u16, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[initialize_operator( + &jito_restaking_program::id(), + config, + operator, + &admin.pubkey(), + &base.pubkey(), + operator_fee_bps, + )], + Some(&admin.pubkey()), + &[admin, base], + blockhash, + )) + .await + } + + pub async fn initialize_operator_vault_ticket( + &mut self, + config: &Pubkey, + operator: &Pubkey, + vault: &Pubkey, + operator_vault_ticket: &Pubkey, + admin: &Keypair, + payer: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[initialize_operator_vault_ticket( + &jito_restaking_program::id(), + config, + operator, + vault, + operator_vault_ticket, + &admin.pubkey(), + &payer.pubkey(), + )], + Some(&payer.pubkey()), + &[admin, payer], + blockhash, + )) + .await + } + + pub async fn operator_set_fee( + &mut self, + config: &Pubkey, + operator: &Pubkey, + admin: &Keypair, + new_fee_bps: u16, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self.process_transaction(&Transaction::new_signed_with_payer( + &[operator_set_fee( + &jito_restaking_program::id(), + config, + operator, + &admin.pubkey(), + new_fee_bps, + )], + Some(&self.payer.pubkey()), + &[admin, &self.payer], + blockhash, + )) + .await + } + + pub async fn ncn_delegate_token_account( + &mut self, + ncn_pubkey: &Pubkey, + delegate_admin: &Keypair, + token_mint: &Pubkey, + token_account: &Pubkey, + delegate: &Pubkey, + token_program_id: &Pubkey, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.process_transaction(&Transaction::new_signed_with_payer( + &[jito_restaking_sdk::sdk::ncn_delegate_token_account( + &jito_restaking_program::id(), + ncn_pubkey, + &delegate_admin.pubkey(), + token_mint, + token_account, + delegate, + token_program_id, + )], + Some(&self.payer.pubkey()), + &[&self.payer, delegate_admin], + blockhash, + )) + .await + } + + pub async fn operator_delegate_token_account( + &mut self, + operator_pubkey: &Pubkey, + delegate_admin: &Keypair, + token_mint: &Pubkey, + token_account: &Pubkey, + delegate: &Pubkey, + token_program_id: &Pubkey, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.process_transaction(&Transaction::new_signed_with_payer( + &[jito_restaking_sdk::sdk::operator_delegate_token_account( + &jito_restaking_program::id(), + operator_pubkey, + &delegate_admin.pubkey(), + token_mint, + token_account, + delegate, + token_program_id, + )], + Some(&self.payer.pubkey()), + &[&self.payer, delegate_admin], + blockhash, + )) + .await + } + + pub async fn process_transaction(&mut self, tx: &Transaction) -> TestResult<()> { + self.banks_client + .process_transaction_with_preflight_and_commitment( + tx.clone(), + CommitmentLevel::Processed, + ) + .await?; + Ok(()) + } + + pub async fn airdrop(&mut self, to: &Pubkey, sol: f64) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.banks_client + .process_transaction_with_preflight_and_commitment( + Transaction::new_signed_with_payer( + &[transfer(&self.payer.pubkey(), to, sol_to_lamports(sol))], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + ), + CommitmentLevel::Processed, + ) + .await?; + Ok(()) + } + + pub async fn set_config_admin( + &mut self, + config: &Pubkey, + old_admin: &Keypair, + new_admin: &Keypair, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.process_transaction(&Transaction::new_signed_with_payer( + &[set_config_admin( + &jito_restaking_program::id(), + config, + &old_admin.pubkey(), + &new_admin.pubkey(), + )], + Some(&old_admin.pubkey()), + &[old_admin], + blockhash, + )) + .await + } +} + +#[track_caller] +#[inline(always)] +pub fn assert_restaking_error( + test_error: Result, + restaking_error: RestakingError, +) { + assert!(test_error.is_err()); + assert_eq!( + test_error.err().unwrap().to_transaction_error().unwrap(), + TransactionError::InstructionError(0, InstructionError::Custom(restaking_error as u32)) + ); } diff --git a/integration_tests/tests/fixtures/test_builder.rs b/integration_tests/tests/fixtures/test_builder.rs index 74545ef..3b8b04a 100644 --- a/integration_tests/tests/fixtures/test_builder.rs +++ b/integration_tests/tests/fixtures/test_builder.rs @@ -1,14 +1,37 @@ use std::fmt::{Debug, Formatter}; -use solana_program::clock::Clock; +use jito_vault_sdk::inline_mpl_token_metadata; +use solana_program::{ + clock::Clock, native_token::sol_to_lamports, pubkey::Pubkey, system_instruction::transfer, +}; use solana_program_test::{processor, BanksClientError, ProgramTest, ProgramTestContext}; +use solana_sdk::{ + commitment_config::CommitmentLevel, + signature::{Keypair, Signer}, + transaction::Transaction, +}; +use spl_associated_token_account::{ + get_associated_token_address, instruction::create_associated_token_account_idempotent, +}; -use super::{ - restaking_client::{NcnRoot, RestakingProgramClient}, - tip_router_client::TipRouterClient, +use super::{restaking_client::NcnRoot, tip_router_client::TipRouterClient}; +use crate::fixtures::{ + restaking_client::{OperatorRoot, RestakingProgramClient}, + vault_client::{VaultProgramClient, VaultRoot}, TestResult, }; +pub struct ConfiguredVault { + pub vault_program_client: VaultProgramClient, + #[allow(dead_code)] + pub restaking_program_client: RestakingProgramClient, + pub vault_config_admin: Keypair, + pub vault_root: VaultRoot, + #[allow(dead_code)] + pub restaking_config_admin: Keypair, + pub operator_roots: Vec, +} + pub struct TestBuilder { context: ProgramTestContext, } @@ -72,6 +95,13 @@ impl TestBuilder { ) } + pub fn vault_program_client(&self) -> VaultProgramClient { + VaultProgramClient::new( + self.context.banks_client.clone(), + self.context.payer.insecure_clone(), + ) + } + pub async fn setup_ncn(&mut self) -> TestResult { let mut restaking_program_client = self.restaking_program_client(); @@ -81,5 +111,143 @@ impl TestBuilder { Ok(ncn_root) } - // Extend this to setup operators, vaults and relationships as neede + pub async fn transfer(&mut self, to: &Pubkey, sol: f64) -> Result<(), BanksClientError> { + let blockhash = self.context.banks_client.get_latest_blockhash().await?; + self.context + .banks_client + .process_transaction_with_preflight_and_commitment( + Transaction::new_signed_with_payer( + &[transfer( + &self.context.payer.pubkey(), + to, + sol_to_lamports(sol), + )], + Some(&self.context.payer.pubkey()), + &[&self.context.payer], + blockhash, + ), + CommitmentLevel::Processed, + ) + .await + } + + /// Configures a vault with an NCN and operators fully configured + pub async fn setup_vault_with_ncn_and_operators( + &mut self, + deposit_fee_bps: u16, + withdrawal_fee_bps: u16, + reward_fee_bps: u16, + num_operators: u16, + slasher_amounts: &[u64], + ) -> TestResult { + let mut vault_program_client = self.vault_program_client(); + let mut restaking_program_client = self.restaking_program_client(); + + let (vault_config_admin, vault_root) = vault_program_client + .setup_config_and_vault(deposit_fee_bps, withdrawal_fee_bps, reward_fee_bps) + .await?; + let restaking_config_admin = restaking_program_client.do_initialize_config().await?; + + let ncn_root = restaking_program_client.do_initialize_ncn().await?; + + // vault <> ncn + restaking_program_client + .do_initialize_ncn_vault_ticket(&ncn_root, &vault_root.vault_pubkey) + .await?; + self.warp_slot_incremental(1).await.unwrap(); + restaking_program_client + .do_warmup_ncn_vault_ticket(&ncn_root, &vault_root.vault_pubkey) + .await?; + vault_program_client + .do_initialize_vault_ncn_ticket(&vault_root, &ncn_root.ncn_pubkey) + .await?; + self.warp_slot_incremental(1).await.unwrap(); + vault_program_client + .do_warmup_vault_ncn_ticket(&vault_root, &ncn_root.ncn_pubkey) + .await?; + + let mut operator_roots = Vec::with_capacity(num_operators as usize); + for _ in 0..num_operators { + let operator_root = restaking_program_client.do_initialize_operator().await?; + + // ncn <> operator + restaking_program_client + .do_initialize_ncn_operator_state(&ncn_root, &operator_root.operator_pubkey) + .await?; + self.warp_slot_incremental(1).await.unwrap(); + restaking_program_client + .do_ncn_warmup_operator(&ncn_root, &operator_root.operator_pubkey) + .await?; + restaking_program_client + .do_operator_warmup_ncn(&operator_root, &ncn_root.ncn_pubkey) + .await?; + + // vault <> operator + restaking_program_client + .do_initialize_operator_vault_ticket(&operator_root, &vault_root.vault_pubkey) + .await?; + self.warp_slot_incremental(1).await.unwrap(); + restaking_program_client + .do_warmup_operator_vault_ticket(&operator_root, &vault_root.vault_pubkey) + .await?; + vault_program_client + .do_initialize_vault_operator_delegation( + &vault_root, + &operator_root.operator_pubkey, + ) + .await?; + + operator_roots.push(operator_root); + } + + let mut slashers_amounts: Vec<(Keypair, u64)> = Vec::with_capacity(slasher_amounts.len()); + for amount in slasher_amounts { + let slasher = Keypair::new(); + self.transfer(&slasher.pubkey(), 10.0).await?; + + restaking_program_client + .do_initialize_ncn_vault_slasher_ticket( + &ncn_root, + &vault_root.vault_pubkey, + &slasher.pubkey(), + *amount, + ) + .await?; + self.warp_slot_incremental(1).await.unwrap(); + restaking_program_client + .do_warmup_ncn_vault_slasher_ticket( + &ncn_root, + &vault_root.vault_pubkey, + &slasher.pubkey(), + ) + .await?; + + vault_program_client + .do_initialize_vault_ncn_slasher_ticket( + &vault_root, + &ncn_root.ncn_pubkey, + &slasher.pubkey(), + ) + .await?; + self.warp_slot_incremental(1).await.unwrap(); + vault_program_client + .do_warmup_vault_ncn_slasher_ticket( + &vault_root, + &ncn_root.ncn_pubkey, + &slasher.pubkey(), + ) + .await?; + + slashers_amounts.push((slasher, *amount)); + } + + Ok(ConfiguredVault { + vault_program_client, + restaking_program_client, + vault_root, + vault_config_admin, + restaking_config_admin, + operator_roots, + }) + } } diff --git a/integration_tests/tests/fixtures/vault_client.rs b/integration_tests/tests/fixtures/vault_client.rs index 06a9639..7f86a88 100644 --- a/integration_tests/tests/fixtures/vault_client.rs +++ b/integration_tests/tests/fixtures/vault_client.rs @@ -1,8 +1,48 @@ use std::{fmt, fmt::Debug}; -use solana_program::pubkey::Pubkey; -use solana_program_test::BanksClient; -use solana_sdk::signature::Keypair; +use borsh::BorshDeserialize; +use jito_bytemuck::AccountDeserialize; +use jito_restaking_core::{ + ncn_vault_slasher_ticket::NcnVaultSlasherTicket, ncn_vault_ticket::NcnVaultTicket, + operator_vault_ticket::OperatorVaultTicket, +}; +use jito_vault_core::{ + config::Config, vault::Vault, vault_ncn_slasher_operator_ticket::VaultNcnSlasherOperatorTicket, + vault_ncn_slasher_ticket::VaultNcnSlasherTicket, vault_ncn_ticket::VaultNcnTicket, + vault_operator_delegation::VaultOperatorDelegation, + vault_staker_withdrawal_ticket::VaultStakerWithdrawalTicket, + vault_update_state_tracker::VaultUpdateStateTracker, +}; +use jito_vault_sdk::{ + error::VaultError, + instruction::{VaultAdminRole, WithdrawalAllocationMethod}, + sdk::{ + add_delegation, cooldown_delegation, initialize_config, initialize_vault, + set_deposit_capacity, warmup_vault_ncn_slasher_ticket, warmup_vault_ncn_ticket, + }, +}; +use log::info; +use solana_program::{ + clock::Clock, + native_token::sol_to_lamports, + program_pack::Pack, + pubkey::Pubkey, + rent::Rent, + system_instruction::{create_account, transfer}, +}; +use solana_program_test::{BanksClient, BanksClientError}; +use solana_sdk::{ + commitment_config::CommitmentLevel, + instruction::InstructionError, + signature::{Keypair, Signer}, + transaction::{Transaction, TransactionError}, +}; +use spl_associated_token_account::{ + get_associated_token_address, instruction::create_associated_token_account_idempotent, +}; +use spl_token::state::Account as SPLTokenAccount; + +use crate::fixtures::{TestError, TestResult}; pub struct VaultRoot { pub vault_pubkey: Pubkey, @@ -19,7 +59,11 @@ impl Debug for VaultRoot { } } -#[allow(dead_code)] +#[derive(Debug)] +pub struct VaultStakerWithdrawalTicketRoot { + pub base: Pubkey, +} + pub struct VaultProgramClient { banks_client: BanksClient, payer: Keypair, @@ -32,4 +76,1602 @@ impl VaultProgramClient { payer, } } + + pub async fn configure_depositor( + &mut self, + vault_root: &VaultRoot, + depositor: &Pubkey, + amount_to_mint: u64, + ) -> TestResult<()> { + self.airdrop(depositor, 100.0).await?; + let vault = self.get_vault(&vault_root.vault_pubkey).await?; + self.create_ata(&vault.supported_mint, depositor).await?; + self.create_ata(&vault.vrt_mint, depositor).await?; + self.mint_spl_to(&vault.supported_mint, depositor, amount_to_mint) + .await?; + + Ok(()) + } + + pub async fn get_config(&mut self, account: &Pubkey) -> Result { + let account = self.banks_client.get_account(*account).await?.unwrap(); + Ok(*Config::try_from_slice_unchecked(account.data.as_slice())?) + } + + pub async fn get_vault(&mut self, account: &Pubkey) -> Result { + let account = self.banks_client.get_account(*account).await?.unwrap(); + Ok(*Vault::try_from_slice_unchecked(account.data.as_slice())?) + } + + pub async fn get_vault_ncn_ticket( + &mut self, + vault: &Pubkey, + ncn: &Pubkey, + ) -> Result { + let account = VaultNcnTicket::find_program_address(&jito_vault_program::id(), vault, ncn).0; + let account = self.banks_client.get_account(account).await?.unwrap(); + Ok(*VaultNcnTicket::try_from_slice_unchecked( + account.data.as_slice(), + )?) + } + + pub async fn get_vault_operator_delegation( + &mut self, + vault: &Pubkey, + operator: &Pubkey, + ) -> Result { + let account = VaultOperatorDelegation::find_program_address( + &jito_vault_program::id(), + vault, + operator, + ) + .0; + let account = self.banks_client.get_account(account).await?.unwrap(); + Ok(*VaultOperatorDelegation::try_from_slice_unchecked( + account.data.as_slice(), + )?) + } + + pub async fn get_vault_staker_withdrawal_ticket( + &mut self, + vault: &Pubkey, + staker: &Pubkey, + base: &Pubkey, + ) -> Result { + let account = VaultStakerWithdrawalTicket::find_program_address( + &jito_vault_program::id(), + vault, + base, + ) + .0; + let account = self.banks_client.get_account(account).await?.unwrap(); + let withdrawal_ticket = + *VaultStakerWithdrawalTicket::try_from_slice_unchecked(account.data.as_slice())?; + assert_eq!(withdrawal_ticket.staker, *staker); + Ok(withdrawal_ticket) + } + + pub async fn get_vault_ncn_slasher_ticket( + &mut self, + vault: &Pubkey, + ncn: &Pubkey, + slasher: &Pubkey, + ) -> Result { + let account = VaultNcnSlasherTicket::find_program_address( + &jito_vault_program::id(), + vault, + ncn, + slasher, + ) + .0; + let account = self.banks_client.get_account(account).await?.unwrap(); + Ok(*VaultNcnSlasherTicket::try_from_slice_unchecked( + account.data.as_slice(), + )?) + } + + #[allow(dead_code)] + pub async fn get_vault_ncn_slasher_operator_ticket( + &mut self, + vault: &Pubkey, + ncn: &Pubkey, + slasher: &Pubkey, + operator: &Pubkey, + epoch: u64, + ) -> Result { + let account = VaultNcnSlasherOperatorTicket::find_program_address( + &jito_vault_program::id(), + vault, + ncn, + slasher, + operator, + epoch, + ) + .0; + let account = self.banks_client.get_account(account).await?.unwrap(); + Ok(*VaultNcnSlasherOperatorTicket::try_from_slice_unchecked( + account.data.as_slice(), + )?) + } + + pub async fn get_vault_update_state_tracker( + &mut self, + vault: &Pubkey, + epoch: u64, + ) -> Result { + let account = + VaultUpdateStateTracker::find_program_address(&jito_vault_program::id(), vault, epoch) + .0; + let account = self.banks_client.get_account(account).await?.unwrap(); + Ok(*VaultUpdateStateTracker::try_from_slice_unchecked( + account.data.as_slice(), + )?) + } + + pub async fn do_initialize_config(&mut self) -> Result { + let config_admin = Keypair::new(); + + self.airdrop(&config_admin.pubkey(), 1.0).await?; + + let config_pubkey = Config::find_program_address(&jito_vault_program::id()).0; + self.initialize_config(&config_pubkey, &config_admin, &config_admin.pubkey(), 0) + .await?; + + Ok(config_admin) + } + + pub async fn initialize_config( + &mut self, + config: &Pubkey, + config_admin: &Keypair, + program_fee_wallet: &Pubkey, + program_fee_bps: u16, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[initialize_config( + &jito_vault_program::id(), + config, + &config_admin.pubkey(), + &jito_restaking_program::id(), + program_fee_wallet, + program_fee_bps, + )], + Some(&config_admin.pubkey()), + &[config_admin], + blockhash, + )) + .await + } + + pub async fn setup_config_and_vault( + &mut self, + deposit_fee_bps: u16, + withdrawal_fee_bps: u16, + reward_fee_bps: u16, + ) -> Result<(Keypair, VaultRoot), TestError> { + let config_admin = self.do_initialize_config().await?; + let vault_root = self + .do_initialize_vault( + deposit_fee_bps, + withdrawal_fee_bps, + reward_fee_bps, + 9, + &config_admin.pubkey(), + ) + .await?; + + Ok((config_admin, vault_root)) + } + + pub async fn do_initialize_vault( + &mut self, + deposit_fee_bps: u16, + withdrawal_fee_bps: u16, + reward_fee_bps: u16, + decimals: u8, + program_fee_wallet: &Pubkey, + ) -> Result { + let vault_base = Keypair::new(); + + let vault_pubkey = + Vault::find_program_address(&jito_vault_program::id(), &vault_base.pubkey()).0; + + let vrt_mint = Keypair::new(); + let vault_admin = Keypair::new(); + let token_mint = Keypair::new(); + + self.airdrop(&vault_admin.pubkey(), 100.0).await?; + self.create_token_mint(&token_mint, &spl_token::id()) + .await?; + + self.initialize_vault( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_pubkey, + &vrt_mint, + &token_mint, + &vault_admin, + &vault_base, + deposit_fee_bps, + withdrawal_fee_bps, + reward_fee_bps, + decimals, + ) + .await?; + + // for holding the backed asset in the vault + self.create_ata(&token_mint.pubkey(), &vault_pubkey).await?; + // for holding fees + self.create_ata(&vrt_mint.pubkey(), &vault_admin.pubkey()) + .await?; + // for holding program fee + self.create_ata(&vrt_mint.pubkey(), program_fee_wallet) + .await?; + + // for holding program fee + Ok(VaultRoot { + vault_admin, + vault_pubkey, + }) + } + + pub async fn do_initialize_vault_ncn_ticket( + &mut self, + vault_root: &VaultRoot, + ncn: &Pubkey, + ) -> Result<(), TestError> { + let vault_ncn_ticket = VaultNcnTicket::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + ncn, + ) + .0; + let ncn_vault_ticket = NcnVaultTicket::find_program_address( + &jito_restaking_program::id(), + ncn, + &vault_root.vault_pubkey, + ) + .0; + self.initialize_vault_ncn_ticket( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + ncn, + &ncn_vault_ticket, + &vault_ncn_ticket, + &vault_root.vault_admin, + &self.payer.insecure_clone(), + ) + .await?; + + Ok(()) + } + + pub async fn set_capacity( + &mut self, + config: &Pubkey, + vault: &Pubkey, + admin: &Keypair, + capacity: u64, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[set_deposit_capacity( + &jito_vault_program::id(), + config, + vault, + &admin.pubkey(), + capacity, + )], + Some(&admin.pubkey()), + &[&admin], + blockhash, + )) + .await + } + + pub async fn do_warmup_vault_ncn_ticket( + &mut self, + vault_root: &VaultRoot, + ncn: &Pubkey, + ) -> Result<(), TestError> { + let vault_ncn_ticket = VaultNcnTicket::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + ncn, + ) + .0; + + self.warmup_vault_ncn_ticket( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + ncn, + &vault_ncn_ticket, + &vault_root.vault_admin, + ) + .await?; + + Ok(()) + } + + pub async fn warmup_vault_ncn_ticket( + &mut self, + config: &Pubkey, + vault: &Pubkey, + ncn: &Pubkey, + vault_ncn_ticket: &Pubkey, + ncn_vault_admin: &Keypair, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[warmup_vault_ncn_ticket( + &jito_vault_program::id(), + config, + vault, + ncn, + vault_ncn_ticket, + &ncn_vault_admin.pubkey(), + )], + Some(&ncn_vault_admin.pubkey()), + &[&ncn_vault_admin], + blockhash, + )) + .await + } + + #[allow(dead_code)] + pub async fn setup_vault_ncn_slasher_operator_ticket( + &mut self, + vault_root: &VaultRoot, + ncn_pubkey: &Pubkey, + slasher: &Pubkey, + operator_pubkey: &Pubkey, + ) -> Result<(), TestError> { + let config = self + .get_config(&Config::find_program_address(&jito_vault_program::id()).0) + .await + .unwrap(); + let clock: Clock = self.banks_client.get_sysvar().await?; + + let vault_ncn_slasher_ticket = VaultNcnSlasherTicket::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + ncn_pubkey, + slasher, + ) + .0; + let vault_ncn_slasher_operator_ticket = + VaultNcnSlasherOperatorTicket::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + ncn_pubkey, + slasher, + operator_pubkey, + clock.slot / config.epoch_length(), + ) + .0; + self.initialize_vault_ncn_slasher_operator_ticket( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + ncn_pubkey, + slasher, + operator_pubkey, + &vault_ncn_slasher_ticket, + &vault_ncn_slasher_operator_ticket, + &self.payer.insecure_clone(), + ) + .await + .unwrap(); + + Ok(()) + } + + pub async fn do_initialize_vault_operator_delegation( + &mut self, + vault_root: &VaultRoot, + operator_pubkey: &Pubkey, + ) -> Result<(), TestError> { + let vault_operator_delegation = VaultOperatorDelegation::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + operator_pubkey, + ) + .0; + let operator_vault_ticket = OperatorVaultTicket::find_program_address( + &jito_restaking_program::id(), + operator_pubkey, + &vault_root.vault_pubkey, + ) + .0; + self.initialize_vault_operator_delegation( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + operator_pubkey, + &operator_vault_ticket, + &vault_operator_delegation, + &vault_root.vault_admin, + &vault_root.vault_admin, + ) + .await?; + + Ok(()) + } + + pub async fn do_initialize_vault_ncn_slasher_ticket( + &mut self, + vault_root: &VaultRoot, + ncn_pubkey: &Pubkey, + slasher: &Pubkey, + ) -> Result<(), TestError> { + let vault_slasher_ticket_pubkey = VaultNcnSlasherTicket::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + ncn_pubkey, + slasher, + ) + .0; + let ncn_slasher_ticket_pubkey = NcnVaultSlasherTicket::find_program_address( + &jito_restaking_program::id(), + ncn_pubkey, + &vault_root.vault_pubkey, + slasher, + ) + .0; + + self.initialize_vault_ncn_slasher_ticket( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + ncn_pubkey, + slasher, + &ncn_slasher_ticket_pubkey, + &vault_slasher_ticket_pubkey, + &vault_root.vault_admin, + &vault_root.vault_admin, + ) + .await?; + + Ok(()) + } + + pub async fn do_warmup_vault_ncn_slasher_ticket( + &mut self, + vault_root: &VaultRoot, + ncn_pubkey: &Pubkey, + slasher: &Pubkey, + ) -> Result<(), TestError> { + let vault_slasher_ticket_pubkey = VaultNcnSlasherTicket::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + ncn_pubkey, + slasher, + ) + .0; + + self.warmup_vault_ncn_slasher_ticket( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + ncn_pubkey, + slasher, + &vault_slasher_ticket_pubkey, + &vault_root.vault_admin, + ) + .await?; + + Ok(()) + } + + pub async fn warmup_vault_ncn_slasher_ticket( + &mut self, + config: &Pubkey, + vault: &Pubkey, + ncn: &Pubkey, + slasher: &Pubkey, + vault_ncn_slasher_ticket: &Pubkey, + admin: &Keypair, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[warmup_vault_ncn_slasher_ticket( + &jito_vault_program::id(), + config, + vault, + ncn, + slasher, + vault_ncn_slasher_ticket, + &admin.pubkey(), + )], + Some(&admin.pubkey()), + &[admin], + blockhash, + )) + .await + } + + pub async fn do_add_delegation( + &mut self, + vault_root: &VaultRoot, + operator: &Pubkey, + amount: u64, + ) -> Result<(), TestError> { + self.add_delegation( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + operator, + &VaultOperatorDelegation::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + operator, + ) + .0, + &vault_root.vault_admin, + amount, + ) + .await?; + + Ok(()) + } + + pub async fn initialize_vault( + &mut self, + config: &Pubkey, + vault: &Pubkey, + vrt_mint: &Keypair, + token_mint: &Keypair, + vault_admin: &Keypair, + vault_base: &Keypair, + deposit_fee_bps: u16, + withdrawal_fee_bps: u16, + reward_fee_bps: u16, + decimals: u8, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[initialize_vault( + &jito_vault_program::id(), + config, + vault, + &vrt_mint.pubkey(), + &token_mint.pubkey(), + &vault_admin.pubkey(), + &vault_base.pubkey(), + deposit_fee_bps, + withdrawal_fee_bps, + reward_fee_bps, + decimals, + )], + Some(&vault_admin.pubkey()), + &[&vault_admin, &vrt_mint, &vault_base], + blockhash, + )) + .await + } + + pub async fn initialize_vault_ncn_ticket( + &mut self, + config: &Pubkey, + vault: &Pubkey, + ncn: &Pubkey, + ncn_vault_ticket: &Pubkey, + vault_ncn_ticket: &Pubkey, + admin: &Keypair, + payer: &Keypair, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::initialize_vault_ncn_ticket( + &jito_vault_program::id(), + config, + vault, + ncn, + ncn_vault_ticket, + vault_ncn_ticket, + &admin.pubkey(), + &payer.pubkey(), + )], + Some(&payer.pubkey()), + &[admin, payer], + blockhash, + )) + .await + } + + pub async fn initialize_vault_operator_delegation( + &mut self, + config: &Pubkey, + vault: &Pubkey, + operator: &Pubkey, + operator_vault_ticket: &Pubkey, + vault_operator_delegation: &Pubkey, + admin: &Keypair, + payer: &Keypair, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::initialize_vault_operator_delegation( + &jito_vault_program::id(), + config, + vault, + operator, + operator_vault_ticket, + vault_operator_delegation, + &admin.pubkey(), + &payer.pubkey(), + )], + Some(&payer.pubkey()), + &[admin, payer], + blockhash, + )) + .await + } + + pub async fn delegate_token_account( + &mut self, + config: &Pubkey, + vault: &Pubkey, + delegate_asset_admin: &Keypair, + token_mint: &Pubkey, + token_account: &Pubkey, + delegate: &Pubkey, + token_program_id: &Pubkey, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::delegate_token_account( + &jito_vault_program::id(), + config, + vault, + &delegate_asset_admin.pubkey(), + token_mint, + token_account, + delegate, + token_program_id, + )], + Some(&self.payer.pubkey()), + &[&self.payer, delegate_asset_admin], + blockhash, + )) + .await + } + + pub async fn set_admin( + &mut self, + config: &Pubkey, + vault: &Pubkey, + old_admin: &Keypair, + new_admin: &Keypair, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::set_admin( + &jito_vault_program::id(), + config, + vault, + &old_admin.pubkey(), + &new_admin.pubkey(), + )], + Some(&old_admin.pubkey()), + &[old_admin, new_admin], + blockhash, + )) + .await + } + + pub async fn set_secondary_admin( + &mut self, + config: &Pubkey, + vault: &Pubkey, + admin: &Keypair, + new_admin: &Pubkey, + role: VaultAdminRole, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::set_secondary_admin( + &jito_vault_program::id(), + config, + vault, + &admin.pubkey(), + new_admin, + role, + )], + Some(&admin.pubkey()), + &[admin], + blockhash, + )) + .await + } + + pub async fn set_fees( + &mut self, + config: &Pubkey, + vault: &Pubkey, + fee_admin: &Keypair, + deposit_fee_bps: Option, + withdrawal_fee_bps: Option, + reward_fee_bps: Option, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::set_fees( + &jito_vault_program::id(), + config, + vault, + &fee_admin.pubkey(), + deposit_fee_bps, + withdrawal_fee_bps, + reward_fee_bps, + )], + Some(&fee_admin.pubkey()), + &[fee_admin], + blockhash, + )) + .await + } + + pub async fn set_program_fee( + &mut self, + config_admin: &Keypair, + new_fee_bps: u16, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::set_program_fee( + &jito_vault_program::id(), + &Config::find_program_address(&jito_vault_program::id()).0, + &config_admin.pubkey(), + new_fee_bps, + )], + Some(&config_admin.pubkey()), + &[config_admin], + blockhash, + )) + .await + } + + pub async fn do_enqueue_withdrawal( + &mut self, + vault_root: &VaultRoot, + depositor: &Keypair, + amount: u64, + ) -> Result { + let vault = self.get_vault(&vault_root.vault_pubkey).await.unwrap(); + let depositor_vrt_token_account = + get_associated_token_address(&depositor.pubkey(), &vault.vrt_mint); + + let base = Keypair::new(); + let vault_staker_withdrawal_ticket = VaultStakerWithdrawalTicket::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + &base.pubkey(), + ) + .0; + info!( + "vault_staker_withdrawal_ticket: {:?}", + vault_staker_withdrawal_ticket + ); + let vault_staker_withdrawal_ticket_token_account = + get_associated_token_address(&vault_staker_withdrawal_ticket, &vault.vrt_mint); + + self.create_ata(&vault.vrt_mint, &vault_staker_withdrawal_ticket) + .await?; + + self.enqueue_withdrawal( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + &vault_staker_withdrawal_ticket, + &vault_staker_withdrawal_ticket_token_account, + depositor, + &depositor_vrt_token_account, + &base, + amount, + ) + .await?; + + Ok(VaultStakerWithdrawalTicketRoot { + base: base.pubkey(), + }) + } + + pub async fn do_cooldown_delegation( + &mut self, + vault_root: &VaultRoot, + operator: &Pubkey, + amount: u64, + ) -> TestResult<()> { + self.cooldown_delegation( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + operator, + &VaultOperatorDelegation::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + operator, + ) + .0, + &vault_root.vault_admin, + amount, + ) + .await + } + + pub async fn cooldown_delegation( + &mut self, + config: &Pubkey, + vault: &Pubkey, + operator: &Pubkey, + vault_operator_delegation: &Pubkey, + admin: &Keypair, + amount: u64, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[cooldown_delegation( + &jito_vault_program::id(), + config, + vault, + operator, + vault_operator_delegation, + &admin.pubkey(), + amount, + )], + Some(&self.payer.pubkey()), + &[&self.payer, admin], + blockhash, + )) + .await + } + + pub async fn do_full_vault_update( + &mut self, + vault_pubkey: &Pubkey, + operators: &[Pubkey], + ) -> Result<(), TestError> { + let slot = self.banks_client.get_sysvar::().await?.slot; + + let config = self + .get_config(&Config::find_program_address(&jito_vault_program::id()).0) + .await?; + + let ncn_epoch = slot / config.epoch_length(); + + let vault_update_state_tracker = VaultUpdateStateTracker::find_program_address( + &jito_vault_program::id(), + vault_pubkey, + ncn_epoch, + ) + .0; + self.initialize_vault_update_state_tracker(vault_pubkey, &vault_update_state_tracker) + .await?; + + for i in 0..operators.len() { + let operator_index = (i + ncn_epoch as usize) % operators.len(); + let operator = &operators[operator_index]; + self.crank_vault_update_state_tracker( + vault_pubkey, + operator, + &VaultOperatorDelegation::find_program_address( + &jito_vault_program::id(), + vault_pubkey, + operator, + ) + .0, + &vault_update_state_tracker, + ) + .await?; + } + + self.close_vault_update_state_tracker( + vault_pubkey, + &vault_update_state_tracker, + slot / config.epoch_length(), + ) + .await?; + + self.update_vault_balance(vault_pubkey).await?; + + Ok(()) + } + + pub async fn do_crank_vault_update_state_tracker( + &mut self, + vault: &Pubkey, + operator: &Pubkey, + ) -> TestResult<()> { + let slot = self.banks_client.get_sysvar::().await?.slot; + let config = self + .get_config(&Config::find_program_address(&jito_vault_program::id()).0) + .await?; + let ncn_epoch = slot / config.epoch_length(); + self.crank_vault_update_state_tracker( + vault, + operator, + &VaultOperatorDelegation::find_program_address( + &jito_vault_program::id(), + vault, + operator, + ) + .0, + &VaultUpdateStateTracker::find_program_address( + &jito_vault_program::id(), + vault, + ncn_epoch, + ) + .0, + ) + .await + } + + pub async fn crank_vault_update_state_tracker( + &mut self, + vault: &Pubkey, + operator: &Pubkey, + vault_operator_delegation: &Pubkey, + vault_update_state_tracker: &Pubkey, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::crank_vault_update_state_tracker( + &jito_vault_program::id(), + &Config::find_program_address(&jito_vault_program::id()).0, + vault, + operator, + vault_operator_delegation, + vault_update_state_tracker, + )], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + )) + .await?; + Ok(()) + } + + pub async fn update_vault_balance(&mut self, vault_pubkey: &Pubkey) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + let vault = self.get_vault(vault_pubkey).await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::update_vault_balance( + &jito_vault_program::id(), + &Config::find_program_address(&jito_vault_program::id()).0, + vault_pubkey, + &get_associated_token_address(vault_pubkey, &vault.supported_mint), + &vault.vrt_mint, + &get_associated_token_address(&vault.fee_wallet, &vault.vrt_mint), + &spl_token::ID, + )], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + )) + .await?; + + Ok(()) + } + + pub async fn initialize_vault_update_state_tracker( + &mut self, + vault_pubkey: &Pubkey, + vault_update_state_tracker: &Pubkey, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::initialize_vault_update_state_tracker( + &jito_vault_program::id(), + &Config::find_program_address(&jito_vault_program::id()).0, + vault_pubkey, + vault_update_state_tracker, + &self.payer.pubkey(), + WithdrawalAllocationMethod::Greedy, + )], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + )) + .await?; + Ok(()) + } + + pub async fn close_vault_update_state_tracker( + &mut self, + vault_pubkey: &Pubkey, + vault_update_state_tracker: &Pubkey, + ncn_epoch: u64, + ) -> TestResult<()> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::close_vault_update_state_tracker( + &jito_vault_program::id(), + &Config::find_program_address(&jito_vault_program::id()).0, + vault_pubkey, + vault_update_state_tracker, + &self.payer.pubkey(), + ncn_epoch, + )], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + )) + .await + } + + pub async fn enqueue_withdrawal( + &mut self, + config: &Pubkey, + vault: &Pubkey, + vault_staker_withdrawal_ticket: &Pubkey, + vault_staker_withdrawal_ticket_token_account: &Pubkey, + staker: &Keypair, + staker_vrt_token_account: &Pubkey, + base: &Keypair, + amount: u64, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::enqueue_withdrawal( + &jito_vault_program::id(), + config, + vault, + vault_staker_withdrawal_ticket, + vault_staker_withdrawal_ticket_token_account, + &staker.pubkey(), + staker_vrt_token_account, + &base.pubkey(), + amount, + )], + Some(&staker.pubkey()), + &[staker, base], + blockhash, + )) + .await + } + + pub async fn do_burn_withdrawal_ticket( + &mut self, + vault_root: &VaultRoot, + staker: &Keypair, + vault_staker_withdrawal_ticket_base: &Pubkey, + program_fee_wallet: &Pubkey, + ) -> Result<(), TestError> { + let vault = self.get_vault(&vault_root.vault_pubkey).await.unwrap(); + let vault_staker_withdrawal_ticket = VaultStakerWithdrawalTicket::find_program_address( + &jito_vault_program::id(), + &vault_root.vault_pubkey, + vault_staker_withdrawal_ticket_base, + ) + .0; + + self.burn_withdrawal_ticket( + &Config::find_program_address(&jito_vault_program::id()).0, + &vault_root.vault_pubkey, + &get_associated_token_address(&vault_root.vault_pubkey, &vault.supported_mint), + &vault.vrt_mint, + &staker.pubkey(), + &get_associated_token_address(&staker.pubkey(), &vault.supported_mint), + &vault_staker_withdrawal_ticket, + &get_associated_token_address(&vault_staker_withdrawal_ticket, &vault.vrt_mint), + &get_associated_token_address(&vault.fee_wallet, &vault.vrt_mint), + &get_associated_token_address(program_fee_wallet, &vault.vrt_mint), + ) + .await?; + + Ok(()) + } + + pub async fn burn_withdrawal_ticket( + &mut self, + config: &Pubkey, + vault: &Pubkey, + vault_token_account: &Pubkey, + vrt_mint: &Pubkey, + staker: &Pubkey, + staker_token_account: &Pubkey, + vault_staker_withdrawal_ticket: &Pubkey, + vault_staker_withdrawal_ticket_token_account: &Pubkey, + vault_fee_token_account: &Pubkey, + program_fee_vrt_token_account: &Pubkey, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::burn_withdrawal_ticket( + &jito_vault_program::id(), + config, + vault, + vault_token_account, + vrt_mint, + staker, + staker_token_account, + vault_staker_withdrawal_ticket, + vault_staker_withdrawal_ticket_token_account, + vault_fee_token_account, + program_fee_vrt_token_account, + )], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + )) + .await + } + + pub async fn add_delegation( + &mut self, + config: &Pubkey, + vault: &Pubkey, + operator: &Pubkey, + vault_operator_delegation: &Pubkey, + admin: &Keypair, + amount: u64, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[add_delegation( + &jito_vault_program::id(), + config, + vault, + operator, + vault_operator_delegation, + &admin.pubkey(), + amount, + )], + Some(&admin.pubkey()), + &[admin], + blockhash, + )) + .await + } + + pub async fn do_mint_to( + &mut self, + vault_root: &VaultRoot, + depositor: &Keypair, + amount_in: u64, + min_amount_out: u64, + ) -> TestResult<()> { + let vault = self.get_vault(&vault_root.vault_pubkey).await.unwrap(); + self.mint_to( + &vault_root.vault_pubkey, + &vault.vrt_mint, + depositor, + &get_associated_token_address(&depositor.pubkey(), &vault.supported_mint), + &get_associated_token_address(&vault_root.vault_pubkey, &vault.supported_mint), + &get_associated_token_address(&depositor.pubkey(), &vault.vrt_mint), + &get_associated_token_address(&vault.fee_wallet, &vault.vrt_mint), + None, + amount_in, + min_amount_out, + ) + .await + } + + pub async fn mint_to( + &mut self, + vault: &Pubkey, + vrt_mint: &Pubkey, + depositor: &Keypair, + depositor_token_account: &Pubkey, + vault_token_account: &Pubkey, + depositor_vrt_token_account: &Pubkey, + vault_fee_token_account: &Pubkey, + mint_signer: Option<&Keypair>, + amount_in: u64, + min_amount_out: u64, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + let mut signers = vec![depositor]; + if let Some(signer) = mint_signer { + signers.push(signer); + } + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::mint_to( + &jito_vault_program::id(), + &Config::find_program_address(&jito_vault_program::id()).0, + vault, + vrt_mint, + &depositor.pubkey(), + depositor_token_account, + vault_token_account, + depositor_vrt_token_account, + vault_fee_token_account, + mint_signer.map(|s| s.pubkey()).as_ref(), + amount_in, + min_amount_out, + )], + Some(&depositor.pubkey()), + &signers, + blockhash, + )) + .await + } + + pub async fn initialize_vault_ncn_slasher_ticket( + &mut self, + config: &Pubkey, + vault: &Pubkey, + ncn: &Pubkey, + slasher: &Pubkey, + ncn_slasher_ticket: &Pubkey, + vault_slasher_ticket: &Pubkey, + admin: &Keypair, + payer: &Keypair, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::initialize_vault_ncn_slasher_ticket( + &jito_vault_program::id(), + config, + vault, + ncn, + slasher, + ncn_slasher_ticket, + vault_slasher_ticket, + &admin.pubkey(), + &payer.pubkey(), + )], + Some(&payer.pubkey()), + &[admin, payer], + blockhash, + )) + .await + } + + #[allow(dead_code)] + pub async fn initialize_vault_ncn_slasher_operator_ticket( + &mut self, + config: &Pubkey, + vault: &Pubkey, + ncn: &Pubkey, + slasher: &Pubkey, + operator: &Pubkey, + vault_ncn_slasher_ticket: &Pubkey, + vault_ncn_slasher_operator_ticket: &Pubkey, + payer: &Keypair, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[ + jito_vault_sdk::sdk::initialize_vault_ncn_slasher_operator_ticket( + &jito_vault_program::id(), + config, + vault, + ncn, + slasher, + operator, + vault_ncn_slasher_ticket, + vault_ncn_slasher_operator_ticket, + &payer.pubkey(), + ), + ], + Some(&payer.pubkey()), + &[payer], + blockhash, + )) + .await + } + + pub async fn create_token_metadata( + &mut self, + vault: &Pubkey, + admin: &Keypair, + vrt_mint: &Pubkey, + payer: &Keypair, + metadata: &Pubkey, + name: String, + symbol: String, + uri: String, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::create_token_metadata( + &jito_vault_program::id(), + vault, + &admin.pubkey(), + vrt_mint, + &payer.pubkey(), + metadata, + name, + symbol, + uri, + )], + Some(&payer.pubkey()), + &[admin, payer], + blockhash, + )) + .await + } + + pub async fn update_token_metadata( + &mut self, + vault: &Pubkey, + admin: &Keypair, + vrt_mint: &Pubkey, + metadata: &Pubkey, + name: String, + symbol: String, + uri: String, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::update_token_metadata( + &jito_vault_program::id(), + vault, + &admin.pubkey(), + vrt_mint, + metadata, + name, + symbol, + uri, + )], + Some(&self.payer.pubkey()), + &[&self.payer, admin], + blockhash, + )) + .await + } + + async fn _process_transaction(&mut self, tx: &Transaction) -> Result<(), TestError> { + self.banks_client + .process_transaction_with_preflight_and_commitment( + tx.clone(), + CommitmentLevel::Processed, + ) + .await?; + Ok(()) + } + + pub async fn airdrop(&mut self, to: &Pubkey, sol: f64) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.banks_client + .process_transaction_with_preflight_and_commitment( + Transaction::new_signed_with_payer( + &[transfer(&self.payer.pubkey(), to, sol_to_lamports(sol))], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + ), + CommitmentLevel::Processed, + ) + .await?; + Ok(()) + } + + pub async fn create_token_mint( + &mut self, + mint: &Keypair, + token_program_id: &Pubkey, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + let rent: Rent = self.banks_client.get_sysvar().await?; + let ixs = vec![ + create_account( + &self.payer.pubkey(), + &mint.pubkey(), + rent.minimum_balance(spl_token::state::Mint::LEN), + spl_token::state::Mint::LEN as u64, + token_program_id, + ), + spl_token::instruction::initialize_mint2( + token_program_id, + &mint.pubkey(), + &self.payer.pubkey(), + None, + 9, + ) + .unwrap(), + ]; + self.banks_client + .process_transaction_with_preflight_and_commitment( + Transaction::new_signed_with_payer( + &ixs, + Some(&self.payer.pubkey()), + &[&self.payer, mint], + blockhash, + ), + CommitmentLevel::Processed, + ) + .await?; + Ok(()) + } + + pub async fn create_ata(&mut self, mint: &Pubkey, owner: &Pubkey) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.banks_client + .process_transaction_with_preflight_and_commitment( + Transaction::new_signed_with_payer( + &[create_associated_token_account_idempotent( + &self.payer.pubkey(), + owner, + mint, + &spl_token::id(), + )], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + ), + CommitmentLevel::Processed, + ) + .await?; + Ok(()) + } + + /// Mints tokens to an ATA owned by the `to` address + pub async fn mint_spl_to( + &mut self, + mint: &Pubkey, + to: &Pubkey, + amount: u64, + ) -> Result<(), BanksClientError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.banks_client + .process_transaction_with_preflight_and_commitment( + Transaction::new_signed_with_payer( + &[ + create_associated_token_account_idempotent( + &self.payer.pubkey(), + to, + mint, + &spl_token::id(), + ), + spl_token::instruction::mint_to( + &spl_token::id(), + mint, + &get_associated_token_address(to, mint), + &self.payer.pubkey(), + &[], + amount, + ) + .unwrap(), + ], + Some(&self.payer.pubkey()), + &[&self.payer], + blockhash, + ), + CommitmentLevel::Processed, + ) + .await + } + + pub async fn get_reward_fee_token_account( + &mut self, + vault: &Pubkey, + ) -> Result { + let vault = self.get_vault(vault).await.unwrap(); + + let vault_fee_token_account = + get_associated_token_address(&vault.fee_wallet, &vault.vrt_mint); + + let account = self + .banks_client + .get_account(vault_fee_token_account) + .await + .unwrap() + .unwrap(); + + Ok(SPLTokenAccount::unpack(&account.data).unwrap()) + } + + pub async fn create_and_fund_reward_vault( + &mut self, + vault: &Pubkey, + rewarder: &Keypair, + amount: u64, + ) -> Result<(), BanksClientError> { + let vault_account = self.get_vault(vault).await.unwrap(); + + let rewarder_token_account = + get_associated_token_address(&rewarder.pubkey(), &vault_account.supported_mint); + + let vault_token_account = + get_associated_token_address(vault, &vault_account.supported_mint); + + let blockhash = self.banks_client.get_latest_blockhash().await?; + self.banks_client + .process_transaction_with_preflight_and_commitment( + Transaction::new_signed_with_payer( + &[ + create_associated_token_account_idempotent( + &rewarder.pubkey(), + &vault_token_account, + &vault_account.supported_mint, + &spl_token::id(), + ), + spl_token::instruction::transfer( + &spl_token::id(), + &rewarder_token_account, + &vault_token_account, + &rewarder.pubkey(), + &[], + amount, + ) + .unwrap(), + ], + Some(&rewarder.pubkey()), + &[&rewarder], + blockhash, + ), + CommitmentLevel::Processed, + ) + .await + } + + pub async fn set_program_fee_wallet( + &mut self, + program_fee_admin: &Keypair, + new_fee_wallet: &Pubkey, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::set_program_fee_wallet( + &jito_vault_program::id(), + &Config::find_program_address(&jito_vault_program::id()).0, + &program_fee_admin.pubkey(), + new_fee_wallet, + )], + Some(&program_fee_admin.pubkey()), + &[program_fee_admin], + blockhash, + )) + .await + } + + pub async fn set_is_paused( + &mut self, + vault: &Pubkey, + admin: &Keypair, + is_paused: bool, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::set_is_paused( + &jito_vault_program::id(), + &Config::find_program_address(&jito_vault_program::id()).0, + vault, + &admin.pubkey(), + is_paused, + )], + Some(&admin.pubkey()), + &[admin], + blockhash, + )) + .await + } + + pub async fn set_config_admin( + &mut self, + config: &Pubkey, + old_admin: &Keypair, + new_admin: &Keypair, + ) -> Result<(), TestError> { + let blockhash = self.banks_client.get_latest_blockhash().await?; + self._process_transaction(&Transaction::new_signed_with_payer( + &[jito_vault_sdk::sdk::set_config_admin( + &jito_vault_program::id(), + config, + &old_admin.pubkey(), + &new_admin.pubkey(), + )], + Some(&old_admin.pubkey()), + &[old_admin], + blockhash, + )) + .await + } +} + +#[inline(always)] +#[track_caller] +pub fn assert_vault_error(test_error: Result, vault_error: VaultError) { + assert!(test_error.is_err()); + assert_eq!( + test_error.err().unwrap().to_transaction_error().unwrap(), + TransactionError::InstructionError(0, InstructionError::Custom(vault_error as u32)) + ); } From 7c2d632a1955ace82d014b3942339cae520b7c59 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Wed, 13 Nov 2024 13:34:13 -0800 Subject: [PATCH 10/28] going to merge in Evans work --- .../tests/fixtures/test_builder.rs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/integration_tests/tests/fixtures/test_builder.rs b/integration_tests/tests/fixtures/test_builder.rs index 3b8b04a..8b5ac0f 100644 --- a/integration_tests/tests/fixtures/test_builder.rs +++ b/integration_tests/tests/fixtures/test_builder.rs @@ -102,15 +102,6 @@ impl TestBuilder { ) } - pub async fn setup_ncn(&mut self) -> TestResult { - let mut restaking_program_client = self.restaking_program_client(); - - restaking_program_client.do_initialize_config().await?; - let ncn_root = restaking_program_client.do_initialize_ncn().await?; - - Ok(ncn_root) - } - pub async fn transfer(&mut self, to: &Pubkey, sol: f64) -> Result<(), BanksClientError> { let blockhash = self.context.banks_client.get_latest_blockhash().await?; self.context @@ -131,6 +122,19 @@ impl TestBuilder { .await } + pub async fn setup_ncn(&mut self) -> TestResult { + let mut restaking_program_client = self.restaking_program_client(); + + restaking_program_client.do_initialize_config().await?; + let ncn_root = restaking_program_client.do_initialize_ncn().await?; + + Ok(ncn_root) + } + + pub async fn add_vault_to_ncn(&mut self, ncn_root: &NcnRoot) { + //TODO start here + } + /// Configures a vault with an NCN and operators fully configured pub async fn setup_vault_with_ncn_and_operators( &mut self, From 38f98b5d2ac565a0eb8ec59ae74f9ce8da044d86 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Wed, 13 Nov 2024 14:54:17 -0800 Subject: [PATCH 11/28] getting closer --- .../tests/fixtures/restaking_client.rs | 18 ++++ .../tests/fixtures/test_builder.rs | 95 ++++--------------- .../tests/fixtures/vault_client.rs | 9 ++ 3 files changed, 48 insertions(+), 74 deletions(-) diff --git a/integration_tests/tests/fixtures/restaking_client.rs b/integration_tests/tests/fixtures/restaking_client.rs index ab0d6b1..9abc567 100644 --- a/integration_tests/tests/fixtures/restaking_client.rs +++ b/integration_tests/tests/fixtures/restaking_client.rs @@ -36,12 +36,30 @@ pub struct NcnRoot { pub ncn_admin: Keypair, } +impl Clone for NcnRoot { + fn clone(&self) -> Self { + Self { + ncn_pubkey: self.ncn_pubkey, + ncn_admin: self.ncn_admin.insecure_clone(), + } + } +} + #[derive(Debug)] pub struct OperatorRoot { pub operator_pubkey: Pubkey, pub operator_admin: Keypair, } +impl Clone for OperatorRoot { + fn clone(&self) -> Self { + Self { + operator_pubkey: self.operator_pubkey, + operator_admin: self.operator_admin.insecure_clone(), + } + } +} + pub struct RestakingProgramClient { banks_client: BanksClient, payer: Keypair, diff --git a/integration_tests/tests/fixtures/test_builder.rs b/integration_tests/tests/fixtures/test_builder.rs index cf31494..36781c6 100644 --- a/integration_tests/tests/fixtures/test_builder.rs +++ b/integration_tests/tests/fixtures/test_builder.rs @@ -22,13 +22,8 @@ use crate::fixtures::{ }; pub struct ConfiguredVault { - pub vault_program_client: VaultProgramClient, - #[allow(dead_code)] - pub restaking_program_client: RestakingProgramClient, - pub vault_config_admin: Keypair, + pub ncn_root: NcnRoot, pub vault_root: VaultRoot, - #[allow(dead_code)] - pub restaking_config_admin: Keypair, pub operator_roots: Vec, } @@ -131,35 +126,36 @@ impl TestBuilder { pub async fn setup_ncn(&mut self) -> TestResult { let mut restaking_program_client = self.restaking_program_client(); + let mut vault_program_client = self.vault_program_client(); + vault_program_client.do_initialize_config().await?; restaking_program_client.do_initialize_config().await?; let ncn_root = restaking_program_client.do_initialize_ncn().await?; Ok(ncn_root) } - pub async fn add_vault_to_ncn(&mut self, ncn_root: &NcnRoot) { - //TODO start here - } - - /// Configures a vault with an NCN and operators fully configured - pub async fn setup_vault_with_ncn_and_operators( + pub async fn setup_vault( &mut self, - deposit_fee_bps: u16, - withdrawal_fee_bps: u16, - reward_fee_bps: u16, - num_operators: u16, - slasher_amounts: &[u64], + ncn_root: &NcnRoot, + operator_roots: &[OperatorRoot], ) -> TestResult { let mut vault_program_client = self.vault_program_client(); let mut restaking_program_client = self.restaking_program_client(); - let (vault_config_admin, vault_root) = vault_program_client - .setup_config_and_vault(deposit_fee_bps, withdrawal_fee_bps, reward_fee_bps) + const DEPOSIT_FEE_BPS: u16 = 10; + const WITHDRAWAL_FEE_BPS: u16 = 10; + const REWARD_FEE_BPS: u16 = 10; + + let vault_root = vault_program_client + .do_initialize_vault( + DEPOSIT_FEE_BPS, + WITHDRAWAL_FEE_BPS, + REWARD_FEE_BPS, + 9, + &self.context.payer.pubkey(), + ) .await?; - let restaking_config_admin = restaking_program_client.do_initialize_config().await?; - - let ncn_root = restaking_program_client.do_initialize_ncn().await?; // vault <> ncn restaking_program_client @@ -177,10 +173,7 @@ impl TestBuilder { .do_warmup_vault_ncn_ticket(&vault_root, &ncn_root.ncn_pubkey) .await?; - let mut operator_roots = Vec::with_capacity(num_operators as usize); - for _ in 0..num_operators { - let operator_root = restaking_program_client.do_initialize_operator().await?; - + for operator_root in operator_roots { // ncn <> operator restaking_program_client .do_initialize_ncn_operator_state(&ncn_root, &operator_root.operator_pubkey) @@ -207,58 +200,12 @@ impl TestBuilder { &operator_root.operator_pubkey, ) .await?; - - operator_roots.push(operator_root); - } - - let mut slashers_amounts: Vec<(Keypair, u64)> = Vec::with_capacity(slasher_amounts.len()); - for amount in slasher_amounts { - let slasher = Keypair::new(); - self.transfer(&slasher.pubkey(), 10.0).await?; - - restaking_program_client - .do_initialize_ncn_vault_slasher_ticket( - &ncn_root, - &vault_root.vault_pubkey, - &slasher.pubkey(), - *amount, - ) - .await?; - self.warp_slot_incremental(1).await.unwrap(); - restaking_program_client - .do_warmup_ncn_vault_slasher_ticket( - &ncn_root, - &vault_root.vault_pubkey, - &slasher.pubkey(), - ) - .await?; - - vault_program_client - .do_initialize_vault_ncn_slasher_ticket( - &vault_root, - &ncn_root.ncn_pubkey, - &slasher.pubkey(), - ) - .await?; - self.warp_slot_incremental(1).await.unwrap(); - vault_program_client - .do_warmup_vault_ncn_slasher_ticket( - &vault_root, - &ncn_root.ncn_pubkey, - &slasher.pubkey(), - ) - .await?; - - slashers_amounts.push((slasher, *amount)); } Ok(ConfiguredVault { - vault_program_client, - restaking_program_client, + ncn_root: ncn_root.clone(), vault_root, - vault_config_admin, - restaking_config_admin, - operator_roots, + operator_roots: operator_roots.to_vec(), }) } } diff --git a/integration_tests/tests/fixtures/vault_client.rs b/integration_tests/tests/fixtures/vault_client.rs index 7f86a88..1103900 100644 --- a/integration_tests/tests/fixtures/vault_client.rs +++ b/integration_tests/tests/fixtures/vault_client.rs @@ -49,6 +49,15 @@ pub struct VaultRoot { pub vault_admin: Keypair, } +impl Clone for VaultRoot { + fn clone(&self) -> Self { + Self { + vault_pubkey: self.vault_pubkey, + vault_admin: self.vault_admin.insecure_clone(), + } + } +} + impl Debug for VaultRoot { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( From 40e9381f41551ecf1e2c8b5d837e15693a2834d4 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Thu, 14 Nov 2024 10:30:37 -0800 Subject: [PATCH 12/28] added in vaultOperatorDelegationVotes --- core/src/epoch_snapshot.rs | 144 ++++++++++++++++-- core/src/error.rs | 4 + program/src/initialize_operator_snapshot.rs | 25 +-- ...lize_vault_operator_delegation_snapshot.rs | 75 ++++----- 4 files changed, 188 insertions(+), 60 deletions(-) diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index 8815e18..aae5ef9 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -198,6 +198,7 @@ pub struct OperatorSnapshot { is_active: PodBool, + operator_index: PodU64, operator_fee_bps: PodU16, vault_operator_delegation_count: PodU64, @@ -205,8 +206,53 @@ pub struct OperatorSnapshot { valid_operator_vault_delegations: PodU64, total_votes: PodU128, + reserved: [u8; 256], - reserved: [u8; 128], + // needs to be last item in struct such that it can grow later + vault_operator_votes: [VaultOperatorVotes; 64], +} + +#[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, ShankType)] +#[repr(C)] +pub struct VaultOperatorVotes { + vault: Pubkey, + votes: PodU128, + vault_index: PodU64, + reserved: [u8; 32], +} + +impl Default for VaultOperatorVotes { + fn default() -> Self { + Self { + vault: Pubkey::default(), + vault_index: PodU64::from(u64::MAX), + votes: PodU128::from(0), + reserved: [0; 32], + } + } +} + +impl VaultOperatorVotes { + pub fn new(vault: Pubkey, votes: u128, vault_index: u64) -> Self { + Self { + vault, + vault_index: PodU64::from(vault_index), + votes: PodU128::from(votes), + reserved: [0; 32], + } + } + + pub fn is_empty(&self) -> bool { + self.vault_index() == u64::MAX + } + + pub fn vault_index(&self) -> u64 { + self.vault_index.into() + } + + pub fn votes(&self) -> u128 { + self.votes.into() + } } impl Discriminator for OperatorSnapshot { @@ -214,6 +260,8 @@ impl Discriminator for OperatorSnapshot { } impl OperatorSnapshot { + pub const MAX_VAULT_OPERATOR_VOTES: usize = 64; + #[allow(clippy::too_many_arguments)] pub fn new( operator: Pubkey, @@ -222,10 +270,15 @@ impl OperatorSnapshot { bump: u8, current_slot: u64, is_active: bool, + operator_index: u64, operator_fee_bps: u16, vault_operator_delegation_count: u64, - ) -> Self { - Self { + ) -> Result { + if vault_operator_delegation_count > Self::MAX_VAULT_OPERATOR_VOTES as u64 { + return Err(TipRouterError::TooManyVaultOperatorDelegations); + } + + Ok(Self { operator, ncn, ncn_epoch: PodU64::from(ncn_epoch), @@ -233,13 +286,15 @@ impl OperatorSnapshot { slot_created: PodU64::from(current_slot), slot_finalized: PodU64::from(0), is_active: PodBool::from(is_active), + operator_index: PodU64::from(operator_index), operator_fee_bps: PodU16::from(operator_fee_bps), vault_operator_delegation_count: PodU64::from(vault_operator_delegation_count), vault_operator_delegations_registered: PodU64::from(0), valid_operator_vault_delegations: PodU64::from(0), total_votes: PodU128::from(0), - reserved: [0; 128], - } + reserved: [0; 256], + vault_operator_votes: [VaultOperatorVotes::default(); 64], + }) } pub fn new_active( @@ -248,9 +303,10 @@ impl OperatorSnapshot { ncn_epoch: u64, bump: u8, current_slot: u64, + operator_index: u64, operator_fee_bps: u16, vault_count: u64, - ) -> Self { + ) -> Result { Self::new( operator, ncn, @@ -258,6 +314,7 @@ impl OperatorSnapshot { bump, current_slot, true, + operator_index, operator_fee_bps, vault_count, ) @@ -269,11 +326,22 @@ impl OperatorSnapshot { ncn_epoch: u64, bump: u8, current_slot: u64, - ) -> Self { - let mut snapshot = Self::new(operator, ncn, ncn_epoch, bump, current_slot, false, 0, 0); + operator_index: u64, + ) -> Result { + let mut snapshot = Self::new( + operator, + ncn, + ncn_epoch, + bump, + current_slot, + false, + operator_index, + 0, + 0, + )?; snapshot.slot_finalized = PodU64::from(current_slot); - snapshot + Ok(snapshot) } pub fn seeds(operator: &Pubkey, ncn: &Pubkey, ncn_epoch: u64) -> Vec> { @@ -355,27 +423,55 @@ impl OperatorSnapshot { self.vault_operator_delegations_registered() == self.vault_operator_delegation_count() } + pub fn insert_vault_operator_votes( + &mut self, + vault: Pubkey, + vault_index: u64, + votes: u128, + ) -> Result<(), TipRouterError> { + // Check for duplicate vaults + for vault_operator_vote in self.vault_operator_votes.iter_mut() { + if vault_operator_vote.vault_index() == vault_index { + return Err(TipRouterError::DuplicateVaultOperatorDelegation); + } + } + + if self.vault_operator_delegations_registered() > Self::MAX_VAULT_OPERATOR_VOTES as u64 { + return Err(TipRouterError::TooManyVaultOperatorDelegations); + } + + self.vault_operator_votes[self.vault_operator_delegations_registered() as usize] = + VaultOperatorVotes::new(vault, votes, vault_index); + + Ok(()) + } + pub fn increment_vault_operator_delegation_registration( &mut self, current_slot: u64, - vault_operator_delegations: u64, + vault: Pubkey, + vault_index: u64, votes: u128, ) -> Result<(), TipRouterError> { if self.finalized() { return Err(TipRouterError::VaultOperatorDelegationFinalized); } + self.insert_vault_operator_votes(vault, vault_index, votes)?; + self.vault_operator_delegations_registered = PodU64::from( self.vault_operator_delegations_registered() .checked_add(1) .ok_or(TipRouterError::ArithmeticOverflow)?, ); - self.valid_operator_vault_delegations = PodU64::from( - self.valid_operator_vault_delegations() - .checked_add(vault_operator_delegations) - .ok_or(TipRouterError::ArithmeticOverflow)?, - ); + if votes > 0 { + self.valid_operator_vault_delegations = PodU64::from( + self.valid_operator_vault_delegations() + .checked_add(1) + .ok_or(TipRouterError::ArithmeticOverflow)?, + ); + } self.total_votes = PodU128::from( self.total_votes() @@ -405,6 +501,8 @@ pub struct VaultOperatorDelegationSnapshot { is_active: PodBool, + vault_index: PodU64, + st_mint: Pubkey, total_security: PodU64, total_votes: PodU128, @@ -426,6 +524,7 @@ impl VaultOperatorDelegationSnapshot { bump: u8, current_slot: u64, is_active: bool, + vault_index: u64, st_mint: Pubkey, total_security: u64, total_votes: u128, @@ -438,6 +537,7 @@ impl VaultOperatorDelegationSnapshot { bump, slot_created: PodU64::from(current_slot), is_active: PodBool::from(is_active), + vault_index: PodU64::from(vault_index), st_mint, total_security: PodU64::from(total_security), total_votes: PodU128::from(total_votes), @@ -453,6 +553,7 @@ impl VaultOperatorDelegationSnapshot { bump: u8, current_slot: u64, st_mint: Pubkey, + vault_index: u64, total_security: u64, total_votes: u128, ) -> Self { @@ -464,6 +565,7 @@ impl VaultOperatorDelegationSnapshot { bump, current_slot, true, + vault_index, st_mint, total_security, total_votes, @@ -477,6 +579,7 @@ impl VaultOperatorDelegationSnapshot { ncn_epoch: u64, bump: u8, current_slot: u64, + vault_index: u64, st_mint: Pubkey, ) -> Self { Self::new( @@ -487,6 +590,7 @@ impl VaultOperatorDelegationSnapshot { bump, current_slot, false, + vault_index, st_mint, 0, 0, @@ -501,6 +605,7 @@ impl VaultOperatorDelegationSnapshot { ncn_epoch: u64, bump: u8, current_slot: u64, + vault_index: u64, st_mint: Pubkey, vault_operator_delegation: &VaultOperatorDelegation, weight_table: &WeightTable, @@ -529,6 +634,7 @@ impl VaultOperatorDelegationSnapshot { bump, current_slot, st_mint, + vault_index, total_security, total_votes, )) @@ -603,4 +709,12 @@ impl VaultOperatorDelegationSnapshot { pub fn total_votes(&self) -> u128 { self.total_votes.into() } + + pub fn vault_index(&self) -> u64 { + self.vault_index.into() + } + + pub fn vault(&self) -> Pubkey { + self.vault + } } diff --git a/core/src/error.rs b/core/src/error.rs index 5edef31..b7ba61b 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -60,6 +60,10 @@ pub enum TipRouterError { VaultOperatorDelegationFinalized, #[error("Operator is already finalized - should not happen")] OperatorFinalized, + #[error("Too many vault operator delegations")] + TooManyVaultOperatorDelegations, + #[error("Duplicate vault operator delegation")] + DuplicateVaultOperatorDelegation, } impl DecodeError for TipRouterError { diff --git a/program/src/initialize_operator_snapshot.rs b/program/src/initialize_operator_snapshot.rs index 75ff1ac..f339ff0 100644 --- a/program/src/initialize_operator_snapshot.rs +++ b/program/src/initialize_operator_snapshot.rs @@ -99,6 +99,16 @@ pub fn process_initialize_operator_snapshot( ncn_operator_okay && operator_ncn_okay }; + let (operator_fee_bps, vault_count, operator_index): (u16, u64, u64) = { + let operator_data = operator.data.borrow(); + let operator_account = Operator::try_from_slice_unchecked(&operator_data)?; + ( + operator_account.operator_fee_bps.into(), + operator_account.vault_count(), + operator_account.index(), + ) + }; + let mut operator_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = operator_snapshot.try_borrow_mut_data()?; operator_snapshot_data[0] = OperatorSnapshot::DISCRIMINATOR; @@ -106,24 +116,16 @@ pub fn process_initialize_operator_snapshot( OperatorSnapshot::try_from_slice_unchecked_mut(&mut operator_snapshot_data)?; *operator_snapshot_account = if is_active { - let (operator_fee_bps, vault_count): (u16, u64) = { - let operator_data = operator.data.borrow(); - let operator_account = Operator::try_from_slice_unchecked(&operator_data)?; - ( - operator_account.operator_fee_bps.into(), - operator_account.vault_count(), - ) - }; - OperatorSnapshot::new_active( *operator.key, *ncn.key, ncn_epoch, operator_snapshot_bump, current_slot, + operator_index, operator_fee_bps, vault_count, - ) + )? } else { OperatorSnapshot::new_inactive( *operator.key, @@ -131,7 +133,8 @@ pub fn process_initialize_operator_snapshot( ncn_epoch, operator_snapshot_bump, current_slot, - ) + operator_index, + )? }; // Increment operator registration for an inactive operator diff --git a/program/src/initialize_vault_operator_delegation_snapshot.rs b/program/src/initialize_vault_operator_delegation_snapshot.rs index 147095e..4cfe33f 100644 --- a/program/src/initialize_vault_operator_delegation_snapshot.rs +++ b/program/src/initialize_vault_operator_delegation_snapshot.rs @@ -1,4 +1,4 @@ -use jito_bytemuck::{AccountDeserialize, Discriminator}; +use jito_bytemuck::AccountDeserialize; use jito_jsm_core::{ create_account, loader::{load_signer, load_system_account, load_system_program}, @@ -26,6 +26,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( accounts: &[AccountInfo], first_slot_of_ncn_epoch: Option, ) -> ProgramResult { + //TODO remove payer, system_program, and vault_operator_delegation_snapshot let [ncn_config, restaking_config, ncn, operator, vault, vault_ncn_ticket, ncn_vault_ticket, vault_operator_delegation, weight_table, epoch_snapshot, operator_snapshot, vault_operator_delegation_snapshot, payer, vault_program, restaking_program, system_program] = accounts else { @@ -71,10 +72,11 @@ pub fn process_initialize_vault_operator_delegation_snapshot( )?; } - load_system_account(vault_operator_delegation_snapshot, true)?; - load_system_program(system_program)?; - //TODO check that it is not writable - load_signer(payer, false)?; + //TODO redact + // load_system_account(vault_operator_delegation_snapshot, true)?; + // load_system_program(system_program)?; + // //TODO check that it is not writable + // load_signer(payer, false)?; let current_slot = Clock::get()?.slot; let (ncn_epoch, ncn_epoch_length) = @@ -109,28 +111,29 @@ pub fn process_initialize_vault_operator_delegation_snapshot( return Err(ProgramError::InvalidAccountData); } - msg!( - "Initializing vault operator delegation snapshot {} for NCN: {} at epoch: {}", - epoch_snapshot.key, - ncn.key, - ncn_epoch - ); - create_account( - payer, - operator_snapshot, - system_program, - program_id, - &Rent::get()?, - 8_u64 - .checked_add(std::mem::size_of::() as u64) - .unwrap(), - &vault_operator_delegation_snapshot_seeds, - )?; - - let st_mint = { + //TODO redact + // msg!( + // "Initializing vault operator delegation snapshot {} for NCN: {} at epoch: {}", + // epoch_snapshot.key, + // ncn.key, + // ncn_epoch + // ); + // create_account( + // payer, + // operator_snapshot, + // system_program, + // program_id, + // &Rent::get()?, + // 8_u64 + // .checked_add(std::mem::size_of::() as u64) + // .unwrap(), + // &vault_operator_delegation_snapshot_seeds, + // )?; + + let (vault_index, st_mint) = { let vault_data = vault.data.borrow(); let vault_account = Vault::try_from_slice_unchecked(&vault_data)?; - vault_account.supported_mint + (vault_account.vault_index(), vault_account.supported_mint) }; let is_active: bool = { @@ -155,15 +158,16 @@ pub fn process_initialize_vault_operator_delegation_snapshot( vault_ncn_okay && ncn_vault_okay && delegation_dne }; - let mut vault_operator_delegation_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = - operator_snapshot.try_borrow_mut_data()?; - vault_operator_delegation_snapshot_data[0] = VaultOperatorDelegationSnapshot::DISCRIMINATOR; - let vault_operator_delegation_snapshot_account = - VaultOperatorDelegationSnapshot::try_from_slice_unchecked_mut( - &mut vault_operator_delegation_snapshot_data, - )?; + // let mut vault_operator_delegation_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = + // operator_snapshot.try_borrow_mut_data()?; + // vault_operator_delegation_snapshot_data[0] = VaultOperatorDelegationSnapshot::DISCRIMINATOR; + // let vault_operator_delegation_snapshot_account = + // VaultOperatorDelegationSnapshot::try_from_slice_unchecked_mut( + // &mut vault_operator_delegation_snapshot_data, + // )?; - *vault_operator_delegation_snapshot_account = if is_active { + // *vault_operator_delegation_snapshot_account = if is_active { + let vault_operator_delegation_snapshot_account = if is_active { let vault_operator_delegation_data = vault_operator_delegation.data.borrow(); let vault_operator_delegation_account = VaultOperatorDelegation::try_from_slice_unchecked(&vault_operator_delegation_data)?; @@ -179,6 +183,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( ncn_epoch, vault_operator_delegation_snapshot_bump, current_slot, + vault_index, st_mint, vault_operator_delegation_account, weight_table_account, @@ -191,6 +196,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( ncn_epoch, vault_operator_delegation_snapshot_bump, current_slot, + vault_index, st_mint, ) }; @@ -202,7 +208,8 @@ pub fn process_initialize_vault_operator_delegation_snapshot( operator_snapshot_account.increment_vault_operator_delegation_registration( current_slot, - vault_operator_delegation_snapshot_account.total_security(), + vault_operator_delegation_snapshot_account.vault(), + vault_operator_delegation_snapshot_account.vault_index(), vault_operator_delegation_snapshot_account.total_votes(), )?; From 84d9252e7c73a897cfb6f076054daaf630cc3199 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Thu, 14 Nov 2024 10:41:17 -0800 Subject: [PATCH 13/28] working --- core/src/epoch_snapshot.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index aae5ef9..c29fcd6 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -423,23 +423,26 @@ impl OperatorSnapshot { self.vault_operator_delegations_registered() == self.vault_operator_delegation_count() } + pub fn contains_vault_index(&self, vault_index: u64) -> bool { + self.vault_operator_votes + .iter() + .any(|v| v.vault_index() == vault_index) + } + pub fn insert_vault_operator_votes( &mut self, vault: Pubkey, vault_index: u64, votes: u128, ) -> Result<(), TipRouterError> { - // Check for duplicate vaults - for vault_operator_vote in self.vault_operator_votes.iter_mut() { - if vault_operator_vote.vault_index() == vault_index { - return Err(TipRouterError::DuplicateVaultOperatorDelegation); - } - } - if self.vault_operator_delegations_registered() > Self::MAX_VAULT_OPERATOR_VOTES as u64 { return Err(TipRouterError::TooManyVaultOperatorDelegations); } + if self.contains_vault_index(vault_index) { + return Err(TipRouterError::DuplicateVaultOperatorDelegation); + } + self.vault_operator_votes[self.vault_operator_delegations_registered() as usize] = VaultOperatorVotes::new(vault, votes, vault_index); From 27a164abef4112fac3c774b2f16438040bcae227 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Thu, 14 Nov 2024 13:58:59 -0800 Subject: [PATCH 14/28] took out the account --- core/src/epoch_snapshot.rs | 217 +----------------- .../tests/fixtures/tip_router_client.rs | 15 +- ...lize_vault_operator_delegation_snapshot.rs | 101 ++------ 3 files changed, 21 insertions(+), 312 deletions(-) diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index c29fcd6..bb3a1be 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -488,134 +488,16 @@ impl OperatorSnapshot { Ok(()) } -} - -// PDA'd ["OPERATOR_SNAPSHOT", VAULT, OPERATOR, NCN, NCN_EPOCH_SLOT] -#[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, AccountDeserialize, ShankAccount)] -#[repr(C)] -pub struct VaultOperatorDelegationSnapshot { - vault: Pubkey, - operator: Pubkey, - ncn: Pubkey, - ncn_epoch: PodU64, - bump: u8, - - slot_created: PodU64, - - is_active: PodBool, - - vault_index: PodU64, - - st_mint: Pubkey, - total_security: PodU64, - total_votes: PodU128, - - reserved: [u8; 128], -} - -impl Discriminator for VaultOperatorDelegationSnapshot { - const DISCRIMINATOR: u8 = Discriminators::VaultOperatorDelegationSnapshot as u8; -} - -impl VaultOperatorDelegationSnapshot { - #[allow(clippy::too_many_arguments)] - pub fn new( - vault: Pubkey, - operator: Pubkey, - ncn: Pubkey, - ncn_epoch: u64, - bump: u8, - current_slot: u64, - is_active: bool, - vault_index: u64, - st_mint: Pubkey, - total_security: u64, - total_votes: u128, - ) -> Self { - Self { - vault, - operator, - ncn, - ncn_epoch: PodU64::from(ncn_epoch), - bump, - slot_created: PodU64::from(current_slot), - is_active: PodBool::from(is_active), - vault_index: PodU64::from(vault_index), - st_mint, - total_security: PodU64::from(total_security), - total_votes: PodU128::from(total_votes), - reserved: [0; 128], - } - } - #[allow(clippy::too_many_arguments)] - pub fn new_active( - vault: Pubkey, - operator: Pubkey, - ncn: Pubkey, - ncn_epoch: u64, - bump: u8, - current_slot: u64, - st_mint: Pubkey, - vault_index: u64, - total_security: u64, - total_votes: u128, - ) -> Self { - Self::new( - vault, - operator, - ncn, - ncn_epoch, - bump, - current_slot, - true, - vault_index, - st_mint, - total_security, - total_votes, - ) - } - - pub fn new_inactive( - vault: Pubkey, - operator: Pubkey, - ncn: Pubkey, - ncn_epoch: u64, - bump: u8, - current_slot: u64, - vault_index: u64, - st_mint: Pubkey, - ) -> Self { - Self::new( - vault, - operator, - ncn, - ncn_epoch, - bump, - current_slot, - false, - vault_index, - st_mint, - 0, - 0, - ) - } - #[allow(clippy::too_many_arguments)] - pub fn create_snapshot( - vault: Pubkey, - operator: Pubkey, - ncn: Pubkey, - ncn_epoch: u64, - bump: u8, - current_slot: u64, - vault_index: u64, - st_mint: Pubkey, + pub fn calculate_total_votes( vault_operator_delegation: &VaultOperatorDelegation, weight_table: &WeightTable, - ) -> Result { + st_mint: &Pubkey, + ) -> Result { let total_security = vault_operator_delegation .delegation_state .total_security()?; + let precise_total_security = PreciseNumber::new(total_security as u128) .ok_or(TipRouterError::NewPreciseNumberError)?; @@ -629,95 +511,6 @@ impl VaultOperatorDelegationSnapshot { .to_imprecise() .ok_or(TipRouterError::CastToImpreciseNumberError)?; - Ok(Self::new_active( - vault, - operator, - ncn, - ncn_epoch, - bump, - current_slot, - st_mint, - vault_index, - total_security, - total_votes, - )) - } - - pub fn seeds(vault: &Pubkey, operator: &Pubkey, ncn: &Pubkey, ncn_epoch: u64) -> Vec> { - Vec::from_iter( - [ - b"VAULT_OPERATOR_DELEGATION_SNAPSHOT".to_vec(), - vault.to_bytes().to_vec(), - operator.to_bytes().to_vec(), - ncn.to_bytes().to_vec(), - ncn_epoch.to_le_bytes().to_vec(), - ] - .iter() - .cloned(), - ) - } - - pub fn find_program_address( - program_id: &Pubkey, - vault: &Pubkey, - operator: &Pubkey, - ncn: &Pubkey, - ncn_epoch: u64, - ) -> (Pubkey, u8, Vec>) { - let seeds = Self::seeds(vault, operator, ncn, ncn_epoch); - let seeds_iter: Vec<_> = seeds.iter().map(|s| s.as_slice()).collect(); - let (pda, bump) = Pubkey::find_program_address(&seeds_iter, program_id); - (pda, bump, seeds) - } - - pub fn load( - program_id: &Pubkey, - vault: &Pubkey, - operator: &Pubkey, - ncn: &Pubkey, - ncn_epoch: u64, - vault_operator_delegation_snapshot: &AccountInfo, - expect_writable: bool, - ) -> Result<(), ProgramError> { - if vault_operator_delegation_snapshot.owner.ne(program_id) { - msg!("Operator Snapshot account has an invalid owner"); - return Err(ProgramError::InvalidAccountOwner); - } - if vault_operator_delegation_snapshot.data_is_empty() { - msg!("Operator Snapshot account data is empty"); - return Err(ProgramError::InvalidAccountData); - } - if expect_writable && !vault_operator_delegation_snapshot.is_writable { - msg!("Operator Snapshot account is not writable"); - return Err(ProgramError::InvalidAccountData); - } - if vault_operator_delegation_snapshot.data.borrow()[0].ne(&Self::DISCRIMINATOR) { - msg!("Operator Snapshot account discriminator is invalid"); - return Err(ProgramError::InvalidAccountData); - } - if vault_operator_delegation_snapshot - .key - .ne(&Self::find_program_address(program_id, vault, operator, ncn, ncn_epoch).0) - { - msg!("Operator Snapshot account is not at the correct PDA"); - return Err(ProgramError::InvalidAccountData); - } - Ok(()) - } - - pub fn total_security(&self) -> u64 { - self.total_security.into() - } - - pub fn total_votes(&self) -> u128 { - self.total_votes.into() - } - - pub fn vault_index(&self) -> u64 { - self.vault_index.into() - } - - pub fn vault(&self) -> Pubkey { - self.vault + Ok(total_votes) } } diff --git a/integration_tests/tests/fixtures/tip_router_client.rs b/integration_tests/tests/fixtures/tip_router_client.rs index 16f5af2..a69e316 100644 --- a/integration_tests/tests/fixtures/tip_router_client.rs +++ b/integration_tests/tests/fixtures/tip_router_client.rs @@ -12,7 +12,7 @@ use jito_tip_router_client::{ types::ConfigAdminRole, }; use jito_tip_router_core::{ - epoch_snapshot::{EpochSnapshot, OperatorSnapshot, VaultOperatorDelegationSnapshot}, + epoch_snapshot::{EpochSnapshot, OperatorSnapshot}, error::TipRouterError, ncn_config::NcnConfig, tracked_mints::TrackedMints, @@ -587,16 +587,6 @@ impl TipRouterClient { let weight_table = WeightTable::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; - let vault_operator_delegation_snapshot = - VaultOperatorDelegationSnapshot::find_program_address( - &jito_tip_router_program::id(), - &vault, - &operator, - &ncn, - ncn_epoch, - ) - .0; - let ix = InitializeVaultOperatorDelegationSnapshotBuilder::new() .ncn_config(config_pda) .restaking_config(restaking_config) @@ -609,11 +599,8 @@ impl TipRouterClient { .weight_table(weight_table) .epoch_snapshot(epoch_snapshot) .operator_snapshot(operator_snapshot) - .vault_operator_delegation_snapshot(vault_operator_delegation_snapshot) - .payer(self.payer.pubkey()) .vault_program(jito_vault_program::id()) .restaking_program(jito_restaking_program::id()) - .system_program(system_program::id()) .first_slot_of_ncn_epoch(slot) .instruction(); diff --git a/program/src/initialize_vault_operator_delegation_snapshot.rs b/program/src/initialize_vault_operator_delegation_snapshot.rs index 4cfe33f..b7fe402 100644 --- a/program/src/initialize_vault_operator_delegation_snapshot.rs +++ b/program/src/initialize_vault_operator_delegation_snapshot.rs @@ -1,13 +1,9 @@ use jito_bytemuck::AccountDeserialize; -use jito_jsm_core::{ - create_account, - loader::{load_signer, load_system_account, load_system_program}, -}; use jito_restaking_core::{ config::Config, ncn::Ncn, ncn_vault_ticket::NcnVaultTicket, operator::Operator, }; use jito_tip_router_core::{ - epoch_snapshot::{EpochSnapshot, OperatorSnapshot, VaultOperatorDelegationSnapshot}, + epoch_snapshot::{EpochSnapshot, OperatorSnapshot}, loaders::load_ncn_epoch, ncn_config::NcnConfig, weight_table::WeightTable, @@ -18,7 +14,7 @@ use jito_vault_core::{ }; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, - program_error::ProgramError, pubkey::Pubkey, rent::Rent, sysvar::Sysvar, + program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar, }; pub fn process_initialize_vault_operator_delegation_snapshot( @@ -27,7 +23,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( first_slot_of_ncn_epoch: Option, ) -> ProgramResult { //TODO remove payer, system_program, and vault_operator_delegation_snapshot - let [ncn_config, restaking_config, ncn, operator, vault, vault_ncn_ticket, ncn_vault_ticket, vault_operator_delegation, weight_table, epoch_snapshot, operator_snapshot, vault_operator_delegation_snapshot, payer, vault_program, restaking_program, system_program] = + let [ncn_config, restaking_config, ncn, operator, vault, vault_ncn_ticket, ncn_vault_ticket, vault_operator_delegation, weight_table, epoch_snapshot, operator_snapshot, vault_program, restaking_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -72,12 +68,6 @@ pub fn process_initialize_vault_operator_delegation_snapshot( )?; } - //TODO redact - // load_system_account(vault_operator_delegation_snapshot, true)?; - // load_system_program(system_program)?; - // //TODO check that it is not writable - // load_signer(payer, false)?; - let current_slot = Clock::get()?.slot; let (ncn_epoch, ncn_epoch_length) = load_ncn_epoch(restaking_config, current_slot, first_slot_of_ncn_epoch)?; @@ -93,43 +83,6 @@ pub fn process_initialize_vault_operator_delegation_snapshot( true, )?; - let ( - vault_operator_delegation_snapshot_pubkey, - vault_operator_delegation_snapshot_bump, - mut vault_operator_delegation_snapshot_seeds, - ) = VaultOperatorDelegationSnapshot::find_program_address( - program_id, - vault.key, - operator.key, - ncn.key, - ncn_epoch, - ); - vault_operator_delegation_snapshot_seeds.push(vec![vault_operator_delegation_snapshot_bump]); - - if vault_operator_delegation_snapshot_pubkey.ne(operator_snapshot.key) { - msg!("Incorrect vault operator delegation snapshot PDA"); - return Err(ProgramError::InvalidAccountData); - } - - //TODO redact - // msg!( - // "Initializing vault operator delegation snapshot {} for NCN: {} at epoch: {}", - // epoch_snapshot.key, - // ncn.key, - // ncn_epoch - // ); - // create_account( - // payer, - // operator_snapshot, - // system_program, - // program_id, - // &Rent::get()?, - // 8_u64 - // .checked_add(std::mem::size_of::() as u64) - // .unwrap(), - // &vault_operator_delegation_snapshot_seeds, - // )?; - let (vault_index, st_mint) = { let vault_data = vault.data.borrow(); let vault_account = Vault::try_from_slice_unchecked(&vault_data)?; @@ -158,16 +111,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( vault_ncn_okay && ncn_vault_okay && delegation_dne }; - // let mut vault_operator_delegation_snapshot_data: std::cell::RefMut<'_, &mut [u8]> = - // operator_snapshot.try_borrow_mut_data()?; - // vault_operator_delegation_snapshot_data[0] = VaultOperatorDelegationSnapshot::DISCRIMINATOR; - // let vault_operator_delegation_snapshot_account = - // VaultOperatorDelegationSnapshot::try_from_slice_unchecked_mut( - // &mut vault_operator_delegation_snapshot_data, - // )?; - - // *vault_operator_delegation_snapshot_account = if is_active { - let vault_operator_delegation_snapshot_account = if is_active { + let total_votes: u128 = if is_active { let vault_operator_delegation_data = vault_operator_delegation.data.borrow(); let vault_operator_delegation_account = VaultOperatorDelegation::try_from_slice_unchecked(&vault_operator_delegation_data)?; @@ -175,30 +119,15 @@ pub fn process_initialize_vault_operator_delegation_snapshot( let weight_table_data = weight_table.data.borrow(); let weight_table_account = WeightTable::try_from_slice_unchecked(&weight_table_data)?; - //TODO Ending here for the day - VaultOperatorDelegationSnapshot::create_snapshot( - *vault.key, - *operator.key, - *ncn.key, - ncn_epoch, - vault_operator_delegation_snapshot_bump, - current_slot, - vault_index, - st_mint, - vault_operator_delegation_account, - weight_table_account, - )? + let total_votes = OperatorSnapshot::calculate_total_votes( + &vault_operator_delegation_account, + &weight_table_account, + &st_mint, + )?; + + total_votes } else { - VaultOperatorDelegationSnapshot::new_inactive( - *vault.key, - *operator.key, - *ncn.key, - ncn_epoch, - vault_operator_delegation_snapshot_bump, - current_slot, - vault_index, - st_mint, - ) + 0u128 }; // Increment vault operator delegation @@ -208,9 +137,9 @@ pub fn process_initialize_vault_operator_delegation_snapshot( operator_snapshot_account.increment_vault_operator_delegation_registration( current_slot, - vault_operator_delegation_snapshot_account.vault(), - vault_operator_delegation_snapshot_account.vault_index(), - vault_operator_delegation_snapshot_account.total_votes(), + *vault.key, + vault_index, + total_votes, )?; // If operator is finalized, increment operator registration From 1b52c14047a55be89737de917353bf88a8423d2d Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Thu, 14 Nov 2024 15:04:54 -0800 Subject: [PATCH 15/28] tests getting closer --- clients/js/jito_tip_router/accounts/index.ts | 1 - .../accounts/operatorSnapshot.ts | 24 +- .../vaultOperatorDelegationSnapshot.ts | 189 --------------- .../jito_tip_router/errors/jitoTipRouter.ts | 8 + .../jito_tip_router/programs/jitoTipRouter.ts | 1 - clients/js/jito_tip_router/types/index.ts | 1 + .../types/vaultOperatorVotes.ts | 70 ++++++ .../src/generated/accounts/mod.rs | 3 +- .../generated/accounts/operator_snapshot.rs | 7 +- .../vault_operator_delegation_snapshot.rs | 88 ------- .../src/generated/errors/jito_tip_router.rs | 6 + .../src/generated/types/mod.rs | 6 +- .../generated/types/vault_operator_votes.rs | 21 ++ idl/jito_tip_router.json | 117 +++++---- .../tests/fixtures/test_builder.rs | 222 +++++++++++++----- 15 files changed, 364 insertions(+), 400 deletions(-) delete mode 100644 clients/js/jito_tip_router/accounts/vaultOperatorDelegationSnapshot.ts create mode 100644 clients/js/jito_tip_router/types/vaultOperatorVotes.ts delete mode 100644 clients/rust/jito_tip_router/src/generated/accounts/vault_operator_delegation_snapshot.rs create mode 100644 clients/rust/jito_tip_router/src/generated/types/vault_operator_votes.rs diff --git a/clients/js/jito_tip_router/accounts/index.ts b/clients/js/jito_tip_router/accounts/index.ts index de71901..549d9e8 100644 --- a/clients/js/jito_tip_router/accounts/index.ts +++ b/clients/js/jito_tip_router/accounts/index.ts @@ -10,5 +10,4 @@ export * from './epochSnapshot'; export * from './ncnConfig'; export * from './operatorSnapshot'; export * from './trackedMints'; -export * from './vaultOperatorDelegationSnapshot'; export * from './weightTable'; diff --git a/clients/js/jito_tip_router/accounts/operatorSnapshot.ts b/clients/js/jito_tip_router/accounts/operatorSnapshot.ts index ff9dddf..d8c0696 100644 --- a/clients/js/jito_tip_router/accounts/operatorSnapshot.ts +++ b/clients/js/jito_tip_router/accounts/operatorSnapshot.ts @@ -40,6 +40,12 @@ import { type MaybeAccount, type MaybeEncodedAccount, } from '@solana/web3.js'; +import { + getVaultOperatorVotesDecoder, + getVaultOperatorVotesEncoder, + type VaultOperatorVotes, + type VaultOperatorVotesArgs, +} from '../types'; export type OperatorSnapshot = { discriminator: bigint; @@ -50,12 +56,14 @@ export type OperatorSnapshot = { slotCreated: bigint; slotFinalized: bigint; isActive: number; + operatorIndex: bigint; operatorFeeBps: number; vaultOperatorDelegationCount: bigint; vaultOperatorDelegationsRegistered: bigint; validOperatorVaultDelegations: bigint; totalVotes: bigint; reserved: Array; + vaultOperatorVotes: Array; }; export type OperatorSnapshotArgs = { @@ -67,12 +75,14 @@ export type OperatorSnapshotArgs = { slotCreated: number | bigint; slotFinalized: number | bigint; isActive: number; + operatorIndex: number | bigint; operatorFeeBps: number; vaultOperatorDelegationCount: number | bigint; vaultOperatorDelegationsRegistered: number | bigint; validOperatorVaultDelegations: number | bigint; totalVotes: number | bigint; reserved: Array; + vaultOperatorVotes: Array; }; export function getOperatorSnapshotEncoder(): Encoder { @@ -85,12 +95,17 @@ export function getOperatorSnapshotEncoder(): Encoder { ['slotCreated', getU64Encoder()], ['slotFinalized', getU64Encoder()], ['isActive', getBoolEncoder()], + ['operatorIndex', getU64Encoder()], ['operatorFeeBps', getU16Encoder()], ['vaultOperatorDelegationCount', getU64Encoder()], ['vaultOperatorDelegationsRegistered', getU64Encoder()], ['validOperatorVaultDelegations', getU64Encoder()], ['totalVotes', getU128Encoder()], - ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], + ['reserved', getArrayEncoder(getU8Encoder(), { size: 256 })], + [ + 'vaultOperatorVotes', + getArrayEncoder(getVaultOperatorVotesEncoder(), { size: 64 }), + ], ]); } @@ -104,12 +119,17 @@ export function getOperatorSnapshotDecoder(): Decoder { ['slotCreated', getU64Decoder()], ['slotFinalized', getU64Decoder()], ['isActive', getBoolDecoder()], + ['operatorIndex', getU64Decoder()], ['operatorFeeBps', getU16Decoder()], ['vaultOperatorDelegationCount', getU64Decoder()], ['vaultOperatorDelegationsRegistered', getU64Decoder()], ['validOperatorVaultDelegations', getU64Decoder()], ['totalVotes', getU128Decoder()], - ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], + ['reserved', getArrayDecoder(getU8Decoder(), { size: 256 })], + [ + 'vaultOperatorVotes', + getArrayDecoder(getVaultOperatorVotesDecoder(), { size: 64 }), + ], ]); } diff --git a/clients/js/jito_tip_router/accounts/vaultOperatorDelegationSnapshot.ts b/clients/js/jito_tip_router/accounts/vaultOperatorDelegationSnapshot.ts deleted file mode 100644 index c0233f5..0000000 --- a/clients/js/jito_tip_router/accounts/vaultOperatorDelegationSnapshot.ts +++ /dev/null @@ -1,189 +0,0 @@ -/** - * This code was AUTOGENERATED using the kinobi library. - * Please DO NOT EDIT THIS FILE, instead use visitors - * to add features, then rerun kinobi to update it. - * - * @see https://github.com/kinobi-so/kinobi - */ - -import { - assertAccountExists, - assertAccountsExist, - combineCodec, - decodeAccount, - fetchEncodedAccount, - fetchEncodedAccounts, - getAddressDecoder, - getAddressEncoder, - getArrayDecoder, - getArrayEncoder, - getBoolDecoder, - getBoolEncoder, - getStructDecoder, - getStructEncoder, - getU128Decoder, - getU128Encoder, - getU64Decoder, - getU64Encoder, - getU8Decoder, - getU8Encoder, - type Account, - type Address, - type Codec, - type Decoder, - type EncodedAccount, - type Encoder, - type FetchAccountConfig, - type FetchAccountsConfig, - type MaybeAccount, - type MaybeEncodedAccount, -} from '@solana/web3.js'; - -export type VaultOperatorDelegationSnapshot = { - discriminator: bigint; - vault: Address; - operator: Address; - ncn: Address; - ncnEpoch: bigint; - bump: number; - slotCreated: bigint; - isActive: number; - stMint: Address; - totalSecurity: bigint; - totalVotes: bigint; - reserved: Array; -}; - -export type VaultOperatorDelegationSnapshotArgs = { - discriminator: number | bigint; - vault: Address; - operator: Address; - ncn: Address; - ncnEpoch: number | bigint; - bump: number; - slotCreated: number | bigint; - isActive: number; - stMint: Address; - totalSecurity: number | bigint; - totalVotes: number | bigint; - reserved: Array; -}; - -export function getVaultOperatorDelegationSnapshotEncoder(): Encoder { - return getStructEncoder([ - ['discriminator', getU64Encoder()], - ['vault', getAddressEncoder()], - ['operator', getAddressEncoder()], - ['ncn', getAddressEncoder()], - ['ncnEpoch', getU64Encoder()], - ['bump', getU8Encoder()], - ['slotCreated', getU64Encoder()], - ['isActive', getBoolEncoder()], - ['stMint', getAddressEncoder()], - ['totalSecurity', getU64Encoder()], - ['totalVotes', getU128Encoder()], - ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], - ]); -} - -export function getVaultOperatorDelegationSnapshotDecoder(): Decoder { - return getStructDecoder([ - ['discriminator', getU64Decoder()], - ['vault', getAddressDecoder()], - ['operator', getAddressDecoder()], - ['ncn', getAddressDecoder()], - ['ncnEpoch', getU64Decoder()], - ['bump', getU8Decoder()], - ['slotCreated', getU64Decoder()], - ['isActive', getBoolDecoder()], - ['stMint', getAddressDecoder()], - ['totalSecurity', getU64Decoder()], - ['totalVotes', getU128Decoder()], - ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], - ]); -} - -export function getVaultOperatorDelegationSnapshotCodec(): Codec< - VaultOperatorDelegationSnapshotArgs, - VaultOperatorDelegationSnapshot -> { - return combineCodec( - getVaultOperatorDelegationSnapshotEncoder(), - getVaultOperatorDelegationSnapshotDecoder() - ); -} - -export function decodeVaultOperatorDelegationSnapshot< - TAddress extends string = string, ->( - encodedAccount: EncodedAccount -): Account; -export function decodeVaultOperatorDelegationSnapshot< - TAddress extends string = string, ->( - encodedAccount: MaybeEncodedAccount -): MaybeAccount; -export function decodeVaultOperatorDelegationSnapshot< - TAddress extends string = string, ->( - encodedAccount: EncodedAccount | MaybeEncodedAccount -): - | Account - | MaybeAccount { - return decodeAccount( - encodedAccount as MaybeEncodedAccount, - getVaultOperatorDelegationSnapshotDecoder() - ); -} - -export async function fetchVaultOperatorDelegationSnapshot< - TAddress extends string = string, ->( - rpc: Parameters[0], - address: Address, - config?: FetchAccountConfig -): Promise> { - const maybeAccount = await fetchMaybeVaultOperatorDelegationSnapshot( - rpc, - address, - config - ); - assertAccountExists(maybeAccount); - return maybeAccount; -} - -export async function fetchMaybeVaultOperatorDelegationSnapshot< - TAddress extends string = string, ->( - rpc: Parameters[0], - address: Address, - config?: FetchAccountConfig -): Promise> { - const maybeAccount = await fetchEncodedAccount(rpc, address, config); - return decodeVaultOperatorDelegationSnapshot(maybeAccount); -} - -export async function fetchAllVaultOperatorDelegationSnapshot( - rpc: Parameters[0], - addresses: Array
, - config?: FetchAccountsConfig -): Promise[]> { - const maybeAccounts = await fetchAllMaybeVaultOperatorDelegationSnapshot( - rpc, - addresses, - config - ); - assertAccountsExist(maybeAccounts); - return maybeAccounts; -} - -export async function fetchAllMaybeVaultOperatorDelegationSnapshot( - rpc: Parameters[0], - addresses: Array
, - config?: FetchAccountsConfig -): Promise[]> { - const maybeAccounts = await fetchEncodedAccounts(rpc, addresses, config); - return maybeAccounts.map((maybeAccount) => - decodeVaultOperatorDelegationSnapshot(maybeAccount) - ); -} diff --git a/clients/js/jito_tip_router/errors/jitoTipRouter.ts b/clients/js/jito_tip_router/errors/jitoTipRouter.ts index fbc2e38..45acb0f 100644 --- a/clients/js/jito_tip_router/errors/jitoTipRouter.ts +++ b/clients/js/jito_tip_router/errors/jitoTipRouter.ts @@ -70,6 +70,10 @@ export const JITO_TIP_ROUTER_ERROR__NO_OPERATORS = 0x2214; // 8724 export const JITO_TIP_ROUTER_ERROR__VAULT_OPERATOR_DELEGATION_FINALIZED = 0x2215; // 8725 /** OperatorFinalized: Operator is already finalized - should not happen */ export const JITO_TIP_ROUTER_ERROR__OPERATOR_FINALIZED = 0x2216; // 8726 +/** TooManyVaultOperatorDelegations: Too many vault operator delegations */ +export const JITO_TIP_ROUTER_ERROR__TOO_MANY_VAULT_OPERATOR_DELEGATIONS = 0x2217; // 8727 +/** DuplicateVaultOperatorDelegation: Duplicate vault operator delegation */ +export const JITO_TIP_ROUTER_ERROR__DUPLICATE_VAULT_OPERATOR_DELEGATION = 0x2218; // 8728 export type JitoTipRouterError = | typeof JITO_TIP_ROUTER_ERROR__ARITHMETIC_OVERFLOW @@ -79,6 +83,7 @@ export type JitoTipRouterError = | typeof JITO_TIP_ROUTER_ERROR__CONFIG_MINTS_NOT_UPDATED | typeof JITO_TIP_ROUTER_ERROR__DENOMINATOR_IS_ZERO | typeof JITO_TIP_ROUTER_ERROR__DUPLICATE_MINTS_IN_TABLE + | typeof JITO_TIP_ROUTER_ERROR__DUPLICATE_VAULT_OPERATOR_DELEGATION | typeof JITO_TIP_ROUTER_ERROR__FEE_CAP_EXCEEDED | typeof JITO_TIP_ROUTER_ERROR__INCORRECT_FEE_ADMIN | typeof JITO_TIP_ROUTER_ERROR__INCORRECT_NCN @@ -91,6 +96,7 @@ export type JitoTipRouterError = | typeof JITO_TIP_ROUTER_ERROR__NO_OPERATORS | typeof JITO_TIP_ROUTER_ERROR__OPERATOR_FINALIZED | typeof JITO_TIP_ROUTER_ERROR__TOO_MANY_MINTS_FOR_TABLE + | typeof JITO_TIP_ROUTER_ERROR__TOO_MANY_VAULT_OPERATOR_DELEGATIONS | typeof JITO_TIP_ROUTER_ERROR__TRACKED_MINT_LIST_FULL | typeof JITO_TIP_ROUTER_ERROR__TRACKED_MINTS_LOCKED | typeof JITO_TIP_ROUTER_ERROR__VAULT_INDEX_ALREADY_IN_USE @@ -111,6 +117,7 @@ if (process.env.NODE_ENV !== 'production') { [JITO_TIP_ROUTER_ERROR__CONFIG_MINTS_NOT_UPDATED]: `Config supported mints do not match NCN Vault Count`, [JITO_TIP_ROUTER_ERROR__DENOMINATOR_IS_ZERO]: `Zero in the denominator`, [JITO_TIP_ROUTER_ERROR__DUPLICATE_MINTS_IN_TABLE]: `Duplicate mints in table`, + [JITO_TIP_ROUTER_ERROR__DUPLICATE_VAULT_OPERATOR_DELEGATION]: `Duplicate vault operator delegation`, [JITO_TIP_ROUTER_ERROR__FEE_CAP_EXCEEDED]: `Fee cap exceeded`, [JITO_TIP_ROUTER_ERROR__INCORRECT_FEE_ADMIN]: `Incorrect fee admin`, [JITO_TIP_ROUTER_ERROR__INCORRECT_NCN]: `Incorrect NCN`, @@ -123,6 +130,7 @@ if (process.env.NODE_ENV !== 'production') { [JITO_TIP_ROUTER_ERROR__NO_OPERATORS]: `No operators in ncn`, [JITO_TIP_ROUTER_ERROR__OPERATOR_FINALIZED]: `Operator is already finalized - should not happen`, [JITO_TIP_ROUTER_ERROR__TOO_MANY_MINTS_FOR_TABLE]: `Too many mints for table`, + [JITO_TIP_ROUTER_ERROR__TOO_MANY_VAULT_OPERATOR_DELEGATIONS]: `Too many vault operator delegations`, [JITO_TIP_ROUTER_ERROR__TRACKED_MINT_LIST_FULL]: `Tracked mints are at capacity`, [JITO_TIP_ROUTER_ERROR__TRACKED_MINTS_LOCKED]: `Tracked mints are locked for the epoch`, [JITO_TIP_ROUTER_ERROR__VAULT_INDEX_ALREADY_IN_USE]: `Vault index already in use by a different mint`, diff --git a/clients/js/jito_tip_router/programs/jitoTipRouter.ts b/clients/js/jito_tip_router/programs/jitoTipRouter.ts index 00617a2..fabcd39 100644 --- a/clients/js/jito_tip_router/programs/jitoTipRouter.ts +++ b/clients/js/jito_tip_router/programs/jitoTipRouter.ts @@ -31,7 +31,6 @@ export const JITO_TIP_ROUTER_PROGRAM_ADDRESS = export enum JitoTipRouterAccount { EpochSnapshot, OperatorSnapshot, - VaultOperatorDelegationSnapshot, NcnConfig, TrackedMints, WeightTable, diff --git a/clients/js/jito_tip_router/types/index.ts b/clients/js/jito_tip_router/types/index.ts index eb8f884..788abb4 100644 --- a/clients/js/jito_tip_router/types/index.ts +++ b/clients/js/jito_tip_router/types/index.ts @@ -10,4 +10,5 @@ export * from './configAdminRole'; export * from './fee'; export * from './fees'; export * from './mintEntry'; +export * from './vaultOperatorVotes'; export * from './weightEntry'; diff --git a/clients/js/jito_tip_router/types/vaultOperatorVotes.ts b/clients/js/jito_tip_router/types/vaultOperatorVotes.ts new file mode 100644 index 0000000..3c2b8e1 --- /dev/null +++ b/clients/js/jito_tip_router/types/vaultOperatorVotes.ts @@ -0,0 +1,70 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/kinobi-so/kinobi + */ + +import { + combineCodec, + fixDecoderSize, + fixEncoderSize, + getAddressDecoder, + getAddressEncoder, + getBytesDecoder, + getBytesEncoder, + getStructDecoder, + getStructEncoder, + getU128Decoder, + getU128Encoder, + getU64Decoder, + getU64Encoder, + type Address, + type Codec, + type Decoder, + type Encoder, + type ReadonlyUint8Array, +} from '@solana/web3.js'; + +export type VaultOperatorVotes = { + vault: Address; + votes: bigint; + vaultIndex: bigint; + reserved: ReadonlyUint8Array; +}; + +export type VaultOperatorVotesArgs = { + vault: Address; + votes: number | bigint; + vaultIndex: number | bigint; + reserved: ReadonlyUint8Array; +}; + +export function getVaultOperatorVotesEncoder(): Encoder { + return getStructEncoder([ + ['vault', getAddressEncoder()], + ['votes', getU128Encoder()], + ['vaultIndex', getU64Encoder()], + ['reserved', fixEncoderSize(getBytesEncoder(), 32)], + ]); +} + +export function getVaultOperatorVotesDecoder(): Decoder { + return getStructDecoder([ + ['vault', getAddressDecoder()], + ['votes', getU128Decoder()], + ['vaultIndex', getU64Decoder()], + ['reserved', fixDecoderSize(getBytesDecoder(), 32)], + ]); +} + +export function getVaultOperatorVotesCodec(): Codec< + VaultOperatorVotesArgs, + VaultOperatorVotes +> { + return combineCodec( + getVaultOperatorVotesEncoder(), + getVaultOperatorVotesDecoder() + ); +} diff --git a/clients/rust/jito_tip_router/src/generated/accounts/mod.rs b/clients/rust/jito_tip_router/src/generated/accounts/mod.rs index 793ccc8..7b099a2 100644 --- a/clients/rust/jito_tip_router/src/generated/accounts/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/accounts/mod.rs @@ -8,10 +8,9 @@ pub(crate) mod r#epoch_snapshot; pub(crate) mod r#ncn_config; pub(crate) mod r#operator_snapshot; pub(crate) mod r#tracked_mints; -pub(crate) mod r#vault_operator_delegation_snapshot; pub(crate) mod r#weight_table; pub use self::{ r#epoch_snapshot::*, r#ncn_config::*, r#operator_snapshot::*, r#tracked_mints::*, - r#vault_operator_delegation_snapshot::*, r#weight_table::*, + r#weight_table::*, }; diff --git a/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs b/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs index 988e4f1..e2e70fa 100644 --- a/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs @@ -7,6 +7,8 @@ use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::pubkey::Pubkey; +use crate::generated::types::VaultOperatorVotes; + #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct OperatorSnapshot { @@ -26,13 +28,16 @@ pub struct OperatorSnapshot { pub slot_created: u64, pub slot_finalized: u64, pub is_active: bool, + pub operator_index: u64, pub operator_fee_bps: u16, pub vault_operator_delegation_count: u64, pub vault_operator_delegations_registered: u64, pub valid_operator_vault_delegations: u64, pub total_votes: u128, #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] - pub reserved: [u8; 128], + pub reserved: [u8; 256], + #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] + pub vault_operator_votes: [VaultOperatorVotes; 64], } impl OperatorSnapshot { diff --git a/clients/rust/jito_tip_router/src/generated/accounts/vault_operator_delegation_snapshot.rs b/clients/rust/jito_tip_router/src/generated/accounts/vault_operator_delegation_snapshot.rs deleted file mode 100644 index c33af9c..0000000 --- a/clients/rust/jito_tip_router/src/generated/accounts/vault_operator_delegation_snapshot.rs +++ /dev/null @@ -1,88 +0,0 @@ -//! This code was AUTOGENERATED using the kinobi library. -//! Please DO NOT EDIT THIS FILE, instead use visitors -//! to add features, then rerun kinobi to update it. -//! -//! - -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_program::pubkey::Pubkey; - -#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct VaultOperatorDelegationSnapshot { - pub discriminator: u64, - #[cfg_attr( - feature = "serde", - serde(with = "serde_with::As::") - )] - pub vault: Pubkey, - #[cfg_attr( - feature = "serde", - serde(with = "serde_with::As::") - )] - pub operator: Pubkey, - #[cfg_attr( - feature = "serde", - serde(with = "serde_with::As::") - )] - pub ncn: Pubkey, - pub ncn_epoch: u64, - pub bump: u8, - pub slot_created: u64, - pub is_active: bool, - #[cfg_attr( - feature = "serde", - serde(with = "serde_with::As::") - )] - pub st_mint: Pubkey, - pub total_security: u64, - pub total_votes: u128, - #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] - pub reserved: [u8; 128], -} - -impl VaultOperatorDelegationSnapshot { - #[inline(always)] - pub fn from_bytes(data: &[u8]) -> Result { - let mut data = data; - Self::deserialize(&mut data) - } -} - -impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> - for VaultOperatorDelegationSnapshot -{ - type Error = std::io::Error; - - fn try_from( - account_info: &solana_program::account_info::AccountInfo<'a>, - ) -> Result { - let mut data: &[u8] = &(*account_info.data).borrow(); - Self::deserialize(&mut data) - } -} - -#[cfg(feature = "anchor")] -impl anchor_lang::AccountDeserialize for VaultOperatorDelegationSnapshot { - fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { - Ok(Self::deserialize(buf)?) - } -} - -#[cfg(feature = "anchor")] -impl anchor_lang::AccountSerialize for VaultOperatorDelegationSnapshot {} - -#[cfg(feature = "anchor")] -impl anchor_lang::Owner for VaultOperatorDelegationSnapshot { - fn owner() -> Pubkey { - crate::JITO_TIP_ROUTER_ID - } -} - -#[cfg(feature = "anchor-idl-build")] -impl anchor_lang::IdlBuild for VaultOperatorDelegationSnapshot {} - -#[cfg(feature = "anchor-idl-build")] -impl anchor_lang::Discriminator for VaultOperatorDelegationSnapshot { - const DISCRIMINATOR: [u8; 8] = [0; 8]; -} diff --git a/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs b/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs index d1a7ced..60dd7d6 100644 --- a/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs +++ b/clients/rust/jito_tip_router/src/generated/errors/jito_tip_router.rs @@ -93,6 +93,12 @@ pub enum JitoTipRouterError { /// 8726 - Operator is already finalized - should not happen #[error("Operator is already finalized - should not happen")] OperatorFinalized = 0x2216, + /// 8727 - Too many vault operator delegations + #[error("Too many vault operator delegations")] + TooManyVaultOperatorDelegations = 0x2217, + /// 8728 - Duplicate vault operator delegation + #[error("Duplicate vault operator delegation")] + DuplicateVaultOperatorDelegation = 0x2218, } impl solana_program::program_error::PrintProgramError for JitoTipRouterError { diff --git a/clients/rust/jito_tip_router/src/generated/types/mod.rs b/clients/rust/jito_tip_router/src/generated/types/mod.rs index 36abae2..9f74ec9 100644 --- a/clients/rust/jito_tip_router/src/generated/types/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/types/mod.rs @@ -8,6 +8,10 @@ pub(crate) mod r#config_admin_role; pub(crate) mod r#fee; pub(crate) mod r#fees; pub(crate) mod r#mint_entry; +pub(crate) mod r#vault_operator_votes; pub(crate) mod r#weight_entry; -pub use self::{r#config_admin_role::*, r#fee::*, r#fees::*, r#mint_entry::*, r#weight_entry::*}; +pub use self::{ + r#config_admin_role::*, r#fee::*, r#fees::*, r#mint_entry::*, r#vault_operator_votes::*, + r#weight_entry::*, +}; diff --git a/clients/rust/jito_tip_router/src/generated/types/vault_operator_votes.rs b/clients/rust/jito_tip_router/src/generated/types/vault_operator_votes.rs new file mode 100644 index 0000000..43941b5 --- /dev/null +++ b/clients/rust/jito_tip_router/src/generated/types/vault_operator_votes.rs @@ -0,0 +1,21 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! + +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct VaultOperatorVotes { + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub vault: Pubkey, + pub votes: u128, + pub vault_index: u64, + pub reserved: [u8; 32], +} diff --git a/idl/jito_tip_router.json b/idl/jito_tip_router.json index 5afa28b..2d574b5 100644 --- a/idl/jito_tip_router.json +++ b/idl/jito_tip_router.json @@ -690,6 +690,12 @@ "defined": "PodBool" } }, + { + "name": "operatorIndex", + "type": { + "defined": "PodU64" + } + }, { "name": "operatorFeeBps", "type": { @@ -725,74 +731,18 @@ "type": { "array": [ "u8", - 128 + 256 ] } - } - ] - } - }, - { - "name": "VaultOperatorDelegationSnapshot", - "type": { - "kind": "struct", - "fields": [ - { - "name": "vault", - "type": "publicKey" - }, - { - "name": "operator", - "type": "publicKey" - }, - { - "name": "ncn", - "type": "publicKey" - }, - { - "name": "ncnEpoch", - "type": { - "defined": "PodU64" - } - }, - { - "name": "bump", - "type": "u8" - }, - { - "name": "slotCreated", - "type": { - "defined": "PodU64" - } - }, - { - "name": "isActive", - "type": { - "defined": "PodBool" - } - }, - { - "name": "stMint", - "type": "publicKey" - }, - { - "name": "totalSecurity", - "type": { - "defined": "PodU64" - } }, { - "name": "totalVotes", - "type": { - "defined": "PodU128" - } - }, - { - "name": "reserved", + "name": "vaultOperatorVotes", "type": { "array": [ - "u8", - 128 + { + "defined": "VaultOperatorVotes" + }, + 64 ] } } @@ -924,6 +874,39 @@ } ], "types": [ + { + "name": "VaultOperatorVotes", + "type": { + "kind": "struct", + "fields": [ + { + "name": "vault", + "type": "publicKey" + }, + { + "name": "votes", + "type": { + "defined": "PodU128" + } + }, + { + "name": "vaultIndex", + "type": { + "defined": "PodU64" + } + }, + { + "name": "reserved", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, { "name": "Fees", "type": { @@ -1201,6 +1184,16 @@ "code": 8726, "name": "OperatorFinalized", "msg": "Operator is already finalized - should not happen" + }, + { + "code": 8727, + "name": "TooManyVaultOperatorDelegations", + "msg": "Too many vault operator delegations" + }, + { + "code": 8728, + "name": "DuplicateVaultOperatorDelegation", + "msg": "Duplicate vault operator delegation" } ], "metadata": { diff --git a/integration_tests/tests/fixtures/test_builder.rs b/integration_tests/tests/fixtures/test_builder.rs index 36781c6..b3b265e 100644 --- a/integration_tests/tests/fixtures/test_builder.rs +++ b/integration_tests/tests/fixtures/test_builder.rs @@ -1,5 +1,7 @@ use std::fmt::{Debug, Formatter}; +use jito_restaking_core::ncn_vault_ticket::{self, NcnVaultTicket}; +use jito_vault_core::vault_ncn_ticket::VaultNcnTicket; use jito_vault_sdk::inline_mpl_token_metadata; use solana_program::{ clock::Clock, native_token::sol_to_lamports, pubkey::Pubkey, system_instruction::transfer, @@ -14,17 +16,32 @@ use spl_associated_token_account::{ get_associated_token_address, instruction::create_associated_token_account_idempotent, }; -use super::{restaking_client::NcnRoot, tip_router_client::TipRouterClient}; +use super::{ + restaking_client::{self, NcnRoot}, + tip_router_client::TipRouterClient, + vault_client, +}; use crate::fixtures::{ restaking_client::{OperatorRoot, RestakingProgramClient}, vault_client::{VaultProgramClient, VaultRoot}, TestResult, }; -pub struct ConfiguredVault { +pub struct TestNcn { pub ncn_root: NcnRoot, + pub operators: Vec, + pub vaults: Vec, +} + +//TODO implement for more fine-grained relationship control +pub struct TestNcnNode { + pub ncn_root: NcnRoot, + pub operator_root: OperatorRoot, pub vault_root: VaultRoot, - pub operator_roots: Vec, + + pub ncn_vault_connected: bool, + pub operator_vault_connected: bool, + pub delegation: u64, } pub struct TestBuilder { @@ -135,77 +152,176 @@ impl TestBuilder { Ok(ncn_root) } - pub async fn setup_vault( - &mut self, - ncn_root: &NcnRoot, - operator_roots: &[OperatorRoot], - ) -> TestResult { + // 1. Setup NCN + pub async fn create_test_ncn(&mut self) -> TestResult { + let mut restaking_program_client = self.restaking_program_client(); let mut vault_program_client = self.vault_program_client(); + let mut tip_router_client = self.tip_router_client(); + + vault_program_client.do_initialize_config().await?; + restaking_program_client.do_initialize_config().await?; + let ncn_root = restaking_program_client.do_initialize_ncn().await?; + + tip_router_client.setup_tip_router(&ncn_root).await?; + + Ok(TestNcn { + ncn_root: ncn_root.clone(), + operators: vec![], + vaults: vec![], + }) + } + + // 2. Setup Operators + pub async fn add_operators_to_test_ncn( + &mut self, + test_ncn: &mut TestNcn, + operator_count: usize, + ) -> TestResult<()> { let mut restaking_program_client = self.restaking_program_client(); - const DEPOSIT_FEE_BPS: u16 = 10; - const WITHDRAWAL_FEE_BPS: u16 = 10; - const REWARD_FEE_BPS: u16 = 10; + for _ in 0..operator_count { + let operator_root = restaking_program_client.do_initialize_operator().await?; - let vault_root = vault_program_client - .do_initialize_vault( - DEPOSIT_FEE_BPS, - WITHDRAWAL_FEE_BPS, - REWARD_FEE_BPS, - 9, - &self.context.payer.pubkey(), - ) - .await?; - - // vault <> ncn - restaking_program_client - .do_initialize_ncn_vault_ticket(&ncn_root, &vault_root.vault_pubkey) - .await?; - self.warp_slot_incremental(1).await.unwrap(); - restaking_program_client - .do_warmup_ncn_vault_ticket(&ncn_root, &vault_root.vault_pubkey) - .await?; - vault_program_client - .do_initialize_vault_ncn_ticket(&vault_root, &ncn_root.ncn_pubkey) - .await?; - self.warp_slot_incremental(1).await.unwrap(); - vault_program_client - .do_warmup_vault_ncn_ticket(&vault_root, &ncn_root.ncn_pubkey) - .await?; - - for operator_root in operator_roots { // ncn <> operator restaking_program_client - .do_initialize_ncn_operator_state(&ncn_root, &operator_root.operator_pubkey) + .do_initialize_ncn_operator_state( + &test_ncn.ncn_root, + &operator_root.operator_pubkey, + ) .await?; self.warp_slot_incremental(1).await.unwrap(); restaking_program_client - .do_ncn_warmup_operator(&ncn_root, &operator_root.operator_pubkey) + .do_ncn_warmup_operator(&test_ncn.ncn_root, &operator_root.operator_pubkey) .await?; restaking_program_client - .do_operator_warmup_ncn(&operator_root, &ncn_root.ncn_pubkey) + .do_operator_warmup_ncn(&operator_root, &test_ncn.ncn_root.ncn_pubkey) + .await?; + + test_ncn.operators.push(operator_root); + } + + Ok(()) + } + + // 3. Setup Vaults + pub async fn add_vaults_to_test_ncn( + &mut self, + test_ncn: &mut TestNcn, + vault_count: usize, + ) -> TestResult<()> { + let mut vault_program_client = self.vault_program_client(); + let mut restaking_program_client = self.restaking_program_client(); + + const DEPOSIT_FEE_BPS: u16 = 10; + const WITHDRAWAL_FEE_BPS: u16 = 10; + const REWARD_FEE_BPS: u16 = 10; + const MINT_AMOUNT: u64 = 1_000_000; + + for _ in 0..vault_count { + let vault_root = vault_program_client + .do_initialize_vault( + DEPOSIT_FEE_BPS, + WITHDRAWAL_FEE_BPS, + REWARD_FEE_BPS, + 9, + &self.context.payer.pubkey(), + ) .await?; - // vault <> operator + // vault <> ncn restaking_program_client - .do_initialize_operator_vault_ticket(&operator_root, &vault_root.vault_pubkey) + .do_initialize_ncn_vault_ticket(&test_ncn.ncn_root, &vault_root.vault_pubkey) .await?; self.warp_slot_incremental(1).await.unwrap(); restaking_program_client - .do_warmup_operator_vault_ticket(&operator_root, &vault_root.vault_pubkey) + .do_warmup_ncn_vault_ticket(&test_ncn.ncn_root, &vault_root.vault_pubkey) .await?; vault_program_client - .do_initialize_vault_operator_delegation( - &vault_root, - &operator_root.operator_pubkey, - ) + .do_initialize_vault_ncn_ticket(&vault_root, &test_ncn.ncn_root.ncn_pubkey) + .await?; + self.warp_slot_incremental(1).await.unwrap(); + vault_program_client + .do_warmup_vault_ncn_ticket(&vault_root, &test_ncn.ncn_root.ncn_pubkey) .await?; + + for operator_root in test_ncn.operators.iter() { + // vault <> operator + restaking_program_client + .do_initialize_operator_vault_ticket(&operator_root, &vault_root.vault_pubkey) + .await?; + self.warp_slot_incremental(1).await.unwrap(); + restaking_program_client + .do_warmup_operator_vault_ticket(&operator_root, &vault_root.vault_pubkey) + .await?; + vault_program_client + .do_initialize_vault_operator_delegation( + &vault_root, + &operator_root.operator_pubkey, + ) + .await?; + } + + let depositor_keypair = self.context.payer.insecure_clone(); + let depositor = depositor_keypair.pubkey(); + vault_program_client + .configure_depositor(&vault_root, &depositor, MINT_AMOUNT) + .await?; + vault_program_client + .do_mint_to(&vault_root, &depositor_keypair, MINT_AMOUNT, MINT_AMOUNT) + .await + .unwrap(); + + test_ncn.vaults.push(vault_root); } - Ok(ConfiguredVault { - ncn_root: ncn_root.clone(), - vault_root, - operator_roots: operator_roots.to_vec(), - }) + Ok(()) + } + + // 4. Setup Delegations + pub async fn add_delegation_in_test_ncn( + &mut self, + test_ncn: &TestNcn, + delegation_amount: usize, + ) -> TestResult<()> { + let mut vault_program_client = self.vault_program_client(); + + for vault_root in test_ncn.vaults.iter() { + for operator_root in test_ncn.operators.iter() { + vault_program_client + .do_add_delegation( + &vault_root, + &operator_root.operator_pubkey, + delegation_amount as u64, + ) + .await + .unwrap(); + } + } + + Ok(()) + } + + // 5. Setup Tracked Mints + pub async fn add_tracked_mints_to_test_ncn(&mut self, test_ncn: &TestNcn) -> TestResult<()> { + let mut tip_router_client = self.tip_router_client(); + let mut vault_client = self.vault_program_client(); + let mut restaking_client = self.restaking_program_client(); + + for vault in test_ncn.vaults.iter() { + let ncn = test_ncn.ncn_root.ncn_pubkey; + let vault = vault.vault_pubkey; + + let vault_ncn_ticket = + VaultNcnTicket::find_program_address(&jito_vault_program::id(), &vault, &ncn).0; + + let ncn_vault_ticket = + NcnVaultTicket::find_program_address(&jito_restaking_program::id(), &ncn, &vault).0; + + tip_router_client + .do_register_mint(ncn, vault, vault_ncn_ticket, ncn_vault_ticket) + .await?; + } + + Ok(()) } } From a3f78b28d4d1ec8ecf89685803724d4732e32193 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Thu, 14 Nov 2024 15:14:14 -0800 Subject: [PATCH 16/28] on the right track --- integration_tests/tests/fixtures/restaking_client.rs | 10 ++++++++-- integration_tests/tests/fixtures/test_builder.rs | 8 ++++++-- integration_tests/tests/tip_router/set_new_admin.rs | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/integration_tests/tests/fixtures/restaking_client.rs b/integration_tests/tests/fixtures/restaking_client.rs index 9abc567..4ebed7d 100644 --- a/integration_tests/tests/fixtures/restaking_client.rs +++ b/integration_tests/tests/fixtures/restaking_client.rs @@ -276,8 +276,14 @@ impl RestakingProgramClient { .await } - pub async fn do_initialize_ncn(&mut self) -> TestResult { - let ncn_admin = Keypair::new(); + pub async fn do_initialize_ncn(&mut self, ncn_admin: Option) -> TestResult { + let ncn_admin = { + if let Some(ncn_admin) = ncn_admin { + ncn_admin + } else { + self.payer.insecure_clone() + } + }; let ncn_base = Keypair::new(); self.airdrop(&ncn_admin.pubkey(), 1.0).await?; diff --git a/integration_tests/tests/fixtures/test_builder.rs b/integration_tests/tests/fixtures/test_builder.rs index b3b265e..8831c93 100644 --- a/integration_tests/tests/fixtures/test_builder.rs +++ b/integration_tests/tests/fixtures/test_builder.rs @@ -147,7 +147,9 @@ impl TestBuilder { vault_program_client.do_initialize_config().await?; restaking_program_client.do_initialize_config().await?; - let ncn_root = restaking_program_client.do_initialize_ncn().await?; + let ncn_root = restaking_program_client + .do_initialize_ncn(Some(self.context.payer.insecure_clone())) + .await?; Ok(ncn_root) } @@ -160,7 +162,9 @@ impl TestBuilder { vault_program_client.do_initialize_config().await?; restaking_program_client.do_initialize_config().await?; - let ncn_root = restaking_program_client.do_initialize_ncn().await?; + let ncn_root = restaking_program_client + .do_initialize_ncn(Some(self.context.payer.insecure_clone())) + .await?; tip_router_client.setup_tip_router(&ncn_root).await?; diff --git a/integration_tests/tests/tip_router/set_new_admin.rs b/integration_tests/tests/tip_router/set_new_admin.rs index af6801c..c0d5813 100644 --- a/integration_tests/tests/tip_router/set_new_admin.rs +++ b/integration_tests/tests/tip_router/set_new_admin.rs @@ -55,7 +55,7 @@ mod tests { fixture.warp_slot_incremental(1).await?; let mut restaking_program_client = fixture.restaking_program_client(); - let wrong_ncn_root = restaking_program_client.do_initialize_ncn().await?; + let wrong_ncn_root = restaking_program_client.do_initialize_ncn(None).await?; let result = tip_router_client .set_new_admin( From 32faa6c166ff1a7685d8a9d5ef2903bf46b14746 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Fri, 15 Nov 2024 10:54:22 -0800 Subject: [PATCH 17/28] working --- integration_tests/tests/tip_router/register_mint.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/integration_tests/tests/tip_router/register_mint.rs b/integration_tests/tests/tip_router/register_mint.rs index 72d7381..7f47ae0 100644 --- a/integration_tests/tests/tip_router/register_mint.rs +++ b/integration_tests/tests/tip_router/register_mint.rs @@ -13,12 +13,10 @@ mod tests { let mut vault_client = fixture.vault_client(); let mut restaking_client = fixture.restaking_program_client(); let ncn_root = fixture.setup_ncn().await?; - - // Setup initial state + // // Setup initial state tip_router_client.setup_tip_router(&ncn_root).await?; - // Setup vault and tickets - let _ = vault_client.do_initialize_config().await?; + // // Setup vault and tickets let vault_root = vault_client .do_initialize_vault(0, 0, 0, 9, &ncn_root.ncn_pubkey) .await?; @@ -114,7 +112,6 @@ mod tests { tip_router_client.setup_tip_router(&ncn_root).await?; // Setup vault and tickets - let _ = vault_client.do_initialize_config().await?; let vault_root = vault_client .do_initialize_vault(0, 0, 0, 9, &ncn_root.ncn_pubkey) .await?; @@ -195,7 +192,6 @@ mod tests { tip_router_client.setup_tip_router(&ncn_root).await?; - let _ = vault_client.do_initialize_config().await?; let vault_root = vault_client .do_initialize_vault(0, 0, 0, 9, &ncn_root.ncn_pubkey) .await?; From d64418a8b227b12fbcfdf0bea31464334a2b1274 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Fri, 15 Nov 2024 13:14:57 -0800 Subject: [PATCH 18/28] serde problem --- ...itializeVaultOperatorDelegationSnapshot.ts | 71 +-------- ...lize_vault_operator_delegation_snapshot.rs | 136 +----------------- core/src/epoch_snapshot.rs | 3 +- core/src/instruction.rs | 7 +- core/src/weight_table.rs | 2 +- idl/jito_tip_router.json | 15 -- .../tests/fixtures/test_builder.rs | 49 ++++++- .../tests/fixtures/tip_router_client.rs | 7 +- .../tip_router/admin_update_weight_table.rs | 18 +-- .../tip_router/initialize_epoch_snapshot.rs | 19 ++- .../initialize_operator_snapshot.rs | 46 ++++++ ...lize_vault_operator_delegation_snapshot.rs | 51 +++++++ .../tip_router/initialize_weight_table.rs | 8 +- integration_tests/tests/tip_router/mod.rs | 2 + program/src/initialize_operator_snapshot.rs | 4 +- ...lize_vault_operator_delegation_snapshot.rs | 15 +- 16 files changed, 198 insertions(+), 255 deletions(-) create mode 100644 integration_tests/tests/tip_router/initialize_operator_snapshot.rs create mode 100644 integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs diff --git a/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts b/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts index cc6c604..35b5b5b 100644 --- a/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts +++ b/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts @@ -22,16 +22,13 @@ import { type Decoder, type Encoder, type IAccountMeta, - type IAccountSignerMeta, type IInstruction, type IInstructionWithAccounts, type IInstructionWithData, type Option, type OptionOrNullable, type ReadonlyAccount, - type TransactionSigner, type WritableAccount, - type WritableSignerAccount, } from '@solana/web3.js'; import { JITO_TIP_ROUTER_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; @@ -59,15 +56,8 @@ export type InitializeVaultOperatorDelegationSnapshotInstruction< TAccountWeightTable extends string | IAccountMeta = string, TAccountEpochSnapshot extends string | IAccountMeta = string, TAccountOperatorSnapshot extends string | IAccountMeta = string, - TAccountVaultOperatorDelegationSnapshot extends - | string - | IAccountMeta = string, - TAccountPayer extends string | IAccountMeta = string, TAccountVaultProgram extends string | IAccountMeta = string, TAccountRestakingProgram extends string | IAccountMeta = string, - TAccountSystemProgram extends - | string - | IAccountMeta = '11111111111111111111111111111111', TRemainingAccounts extends readonly IAccountMeta[] = [], > = IInstruction & IInstructionWithData & @@ -104,22 +94,12 @@ export type InitializeVaultOperatorDelegationSnapshotInstruction< TAccountOperatorSnapshot extends string ? WritableAccount : TAccountOperatorSnapshot, - TAccountVaultOperatorDelegationSnapshot extends string - ? WritableAccount - : TAccountVaultOperatorDelegationSnapshot, - TAccountPayer extends string - ? WritableSignerAccount & - IAccountSignerMeta - : TAccountPayer, TAccountVaultProgram extends string ? ReadonlyAccount : TAccountVaultProgram, TAccountRestakingProgram extends string ? ReadonlyAccount : TAccountRestakingProgram, - TAccountSystemProgram extends string - ? ReadonlyAccount - : TAccountSystemProgram, ...TRemainingAccounts, ] >; @@ -176,11 +156,8 @@ export type InitializeVaultOperatorDelegationSnapshotInput< TAccountWeightTable extends string = string, TAccountEpochSnapshot extends string = string, TAccountOperatorSnapshot extends string = string, - TAccountVaultOperatorDelegationSnapshot extends string = string, - TAccountPayer extends string = string, TAccountVaultProgram extends string = string, TAccountRestakingProgram extends string = string, - TAccountSystemProgram extends string = string, > = { ncnConfig: Address; restakingConfig: Address; @@ -193,11 +170,8 @@ export type InitializeVaultOperatorDelegationSnapshotInput< weightTable: Address; epochSnapshot: Address; operatorSnapshot: Address; - vaultOperatorDelegationSnapshot: Address; - payer: TransactionSigner; vaultProgram: Address; restakingProgram: Address; - systemProgram?: Address; firstSlotOfNcnEpoch: InitializeVaultOperatorDelegationSnapshotInstructionDataArgs['firstSlotOfNcnEpoch']; }; @@ -213,11 +187,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountWeightTable extends string, TAccountEpochSnapshot extends string, TAccountOperatorSnapshot extends string, - TAccountVaultOperatorDelegationSnapshot extends string, - TAccountPayer extends string, TAccountVaultProgram extends string, TAccountRestakingProgram extends string, - TAccountSystemProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( input: InitializeVaultOperatorDelegationSnapshotInput< @@ -232,11 +203,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountWeightTable, TAccountEpochSnapshot, TAccountOperatorSnapshot, - TAccountVaultOperatorDelegationSnapshot, - TAccountPayer, TAccountVaultProgram, - TAccountRestakingProgram, - TAccountSystemProgram + TAccountRestakingProgram >, config?: { programAddress?: TProgramAddress } ): InitializeVaultOperatorDelegationSnapshotInstruction< @@ -252,11 +220,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountWeightTable, TAccountEpochSnapshot, TAccountOperatorSnapshot, - TAccountVaultOperatorDelegationSnapshot, - TAccountPayer, TAccountVaultProgram, - TAccountRestakingProgram, - TAccountSystemProgram + TAccountRestakingProgram > { // Program address. const programAddress = @@ -284,17 +249,11 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< value: input.operatorSnapshot ?? null, isWritable: true, }, - vaultOperatorDelegationSnapshot: { - value: input.vaultOperatorDelegationSnapshot ?? null, - isWritable: true, - }, - payer: { value: input.payer ?? null, isWritable: true }, vaultProgram: { value: input.vaultProgram ?? null, isWritable: false }, restakingProgram: { value: input.restakingProgram ?? null, isWritable: false, }, - systemProgram: { value: input.systemProgram ?? null, isWritable: false }, }; const accounts = originalAccounts as Record< keyof typeof originalAccounts, @@ -304,12 +263,6 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< // Original args. const args = { ...input }; - // Resolve default values. - if (!accounts.systemProgram.value) { - accounts.systemProgram.value = - '11111111111111111111111111111111' as Address<'11111111111111111111111111111111'>; - } - const getAccountMeta = getAccountMetaFactory(programAddress, 'programId'); const instruction = { accounts: [ @@ -324,11 +277,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< getAccountMeta(accounts.weightTable), getAccountMeta(accounts.epochSnapshot), getAccountMeta(accounts.operatorSnapshot), - getAccountMeta(accounts.vaultOperatorDelegationSnapshot), - getAccountMeta(accounts.payer), getAccountMeta(accounts.vaultProgram), getAccountMeta(accounts.restakingProgram), - getAccountMeta(accounts.systemProgram), ], programAddress, data: getInitializeVaultOperatorDelegationSnapshotInstructionDataEncoder().encode( @@ -347,11 +297,8 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountWeightTable, TAccountEpochSnapshot, TAccountOperatorSnapshot, - TAccountVaultOperatorDelegationSnapshot, - TAccountPayer, TAccountVaultProgram, - TAccountRestakingProgram, - TAccountSystemProgram + TAccountRestakingProgram >; return instruction; @@ -374,11 +321,8 @@ export type ParsedInitializeVaultOperatorDelegationSnapshotInstruction< weightTable: TAccountMetas[8]; epochSnapshot: TAccountMetas[9]; operatorSnapshot: TAccountMetas[10]; - vaultOperatorDelegationSnapshot: TAccountMetas[11]; - payer: TAccountMetas[12]; - vaultProgram: TAccountMetas[13]; - restakingProgram: TAccountMetas[14]; - systemProgram: TAccountMetas[15]; + vaultProgram: TAccountMetas[11]; + restakingProgram: TAccountMetas[12]; }; data: InitializeVaultOperatorDelegationSnapshotInstructionData; }; @@ -394,7 +338,7 @@ export function parseInitializeVaultOperatorDelegationSnapshotInstruction< TProgram, TAccountMetas > { - if (instruction.accounts.length < 16) { + if (instruction.accounts.length < 13) { // TODO: Coded error. throw new Error('Not enough accounts'); } @@ -418,11 +362,8 @@ export function parseInitializeVaultOperatorDelegationSnapshotInstruction< weightTable: getNextAccount(), epochSnapshot: getNextAccount(), operatorSnapshot: getNextAccount(), - vaultOperatorDelegationSnapshot: getNextAccount(), - payer: getNextAccount(), vaultProgram: getNextAccount(), restakingProgram: getNextAccount(), - systemProgram: getNextAccount(), }, data: getInitializeVaultOperatorDelegationSnapshotInstructionDataDecoder().decode( instruction.data diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs index 840bc41..a1f8a1e 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs @@ -30,15 +30,9 @@ pub struct InitializeVaultOperatorDelegationSnapshot { pub operator_snapshot: solana_program::pubkey::Pubkey, - pub vault_operator_delegation_snapshot: solana_program::pubkey::Pubkey, - - pub payer: solana_program::pubkey::Pubkey, - pub vault_program: solana_program::pubkey::Pubkey, pub restaking_program: solana_program::pubkey::Pubkey, - - pub system_program: solana_program::pubkey::Pubkey, } impl InitializeVaultOperatorDelegationSnapshot { @@ -54,7 +48,7 @@ impl InitializeVaultOperatorDelegationSnapshot { args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, remaining_accounts: &[solana_program::instruction::AccountMeta], ) -> solana_program::instruction::Instruction { - let mut accounts = Vec::with_capacity(16 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(13 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new_readonly( self.ncn_config, false, @@ -97,13 +91,6 @@ impl InitializeVaultOperatorDelegationSnapshot { self.operator_snapshot, false, )); - accounts.push(solana_program::instruction::AccountMeta::new( - self.vault_operator_delegation_snapshot, - false, - )); - accounts.push(solana_program::instruction::AccountMeta::new( - self.payer, true, - )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( self.vault_program, false, @@ -112,10 +99,6 @@ impl InitializeVaultOperatorDelegationSnapshot { self.restaking_program, false, )); - accounts.push(solana_program::instruction::AccountMeta::new_readonly( - self.system_program, - false, - )); accounts.extend_from_slice(remaining_accounts); let mut data = InitializeVaultOperatorDelegationSnapshotInstructionData::new() .try_to_vec() @@ -169,11 +152,8 @@ pub struct InitializeVaultOperatorDelegationSnapshotInstructionArgs { /// 8. `[]` weight_table /// 9. `[writable]` epoch_snapshot /// 10. `[writable]` operator_snapshot -/// 11. `[writable]` vault_operator_delegation_snapshot -/// 12. `[writable, signer]` payer -/// 13. `[]` vault_program -/// 14. `[]` restaking_program -/// 15. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 11. `[]` vault_program +/// 12. `[]` restaking_program #[derive(Clone, Debug, Default)] pub struct InitializeVaultOperatorDelegationSnapshotBuilder { ncn_config: Option, @@ -187,11 +167,8 @@ pub struct InitializeVaultOperatorDelegationSnapshotBuilder { weight_table: Option, epoch_snapshot: Option, operator_snapshot: Option, - vault_operator_delegation_snapshot: Option, - payer: Option, vault_program: Option, restaking_program: Option, - system_program: Option, first_slot_of_ncn_epoch: Option, __remaining_accounts: Vec, } @@ -271,19 +248,6 @@ impl InitializeVaultOperatorDelegationSnapshotBuilder { self } #[inline(always)] - pub fn vault_operator_delegation_snapshot( - &mut self, - vault_operator_delegation_snapshot: solana_program::pubkey::Pubkey, - ) -> &mut Self { - self.vault_operator_delegation_snapshot = Some(vault_operator_delegation_snapshot); - self - } - #[inline(always)] - pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { - self.payer = Some(payer); - self - } - #[inline(always)] pub fn vault_program(&mut self, vault_program: solana_program::pubkey::Pubkey) -> &mut Self { self.vault_program = Some(vault_program); self @@ -296,12 +260,6 @@ impl InitializeVaultOperatorDelegationSnapshotBuilder { self.restaking_program = Some(restaking_program); self } - /// `[optional account, default to '11111111111111111111111111111111']` - #[inline(always)] - pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { - self.system_program = Some(system_program); - self - } /// `[optional argument]` #[inline(always)] pub fn first_slot_of_ncn_epoch(&mut self, first_slot_of_ncn_epoch: u64) -> &mut Self { @@ -344,17 +302,10 @@ impl InitializeVaultOperatorDelegationSnapshotBuilder { operator_snapshot: self .operator_snapshot .expect("operator_snapshot is not set"), - vault_operator_delegation_snapshot: self - .vault_operator_delegation_snapshot - .expect("vault_operator_delegation_snapshot is not set"), - payer: self.payer.expect("payer is not set"), vault_program: self.vault_program.expect("vault_program is not set"), restaking_program: self .restaking_program .expect("restaking_program is not set"), - system_program: self - .system_program - .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), }; let args = InitializeVaultOperatorDelegationSnapshotInstructionArgs { first_slot_of_ncn_epoch: self.first_slot_of_ncn_epoch.clone(), @@ -388,15 +339,9 @@ pub struct InitializeVaultOperatorDelegationSnapshotCpiAccounts<'a, 'b> { pub operator_snapshot: &'b solana_program::account_info::AccountInfo<'a>, - pub vault_operator_delegation_snapshot: &'b solana_program::account_info::AccountInfo<'a>, - - pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub vault_program: &'b solana_program::account_info::AccountInfo<'a>, pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, - - pub system_program: &'b solana_program::account_info::AccountInfo<'a>, } /// `initialize_vault_operator_delegation_snapshot` CPI instruction. @@ -426,15 +371,9 @@ pub struct InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { pub operator_snapshot: &'b solana_program::account_info::AccountInfo<'a>, - pub vault_operator_delegation_snapshot: &'b solana_program::account_info::AccountInfo<'a>, - - pub payer: &'b solana_program::account_info::AccountInfo<'a>, - pub vault_program: &'b solana_program::account_info::AccountInfo<'a>, pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, - - pub system_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. pub __args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, } @@ -458,11 +397,8 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { weight_table: accounts.weight_table, epoch_snapshot: accounts.epoch_snapshot, operator_snapshot: accounts.operator_snapshot, - vault_operator_delegation_snapshot: accounts.vault_operator_delegation_snapshot, - payer: accounts.payer, vault_program: accounts.vault_program, restaking_program: accounts.restaking_program, - system_program: accounts.system_program, __args: args, } } @@ -499,7 +435,7 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { bool, )], ) -> solana_program::entrypoint::ProgramResult { - let mut accounts = Vec::with_capacity(16 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(13 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new_readonly( *self.ncn_config.key, false, @@ -544,14 +480,6 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { *self.operator_snapshot.key, false, )); - accounts.push(solana_program::instruction::AccountMeta::new( - *self.vault_operator_delegation_snapshot.key, - false, - )); - accounts.push(solana_program::instruction::AccountMeta::new( - *self.payer.key, - true, - )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( *self.vault_program.key, false, @@ -560,10 +488,6 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { *self.restaking_program.key, false, )); - accounts.push(solana_program::instruction::AccountMeta::new_readonly( - *self.system_program.key, - false, - )); remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, @@ -582,7 +506,7 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { accounts, data, }; - let mut account_infos = Vec::with_capacity(16 + 1 + remaining_accounts.len()); + let mut account_infos = Vec::with_capacity(13 + 1 + remaining_accounts.len()); account_infos.push(self.__program.clone()); account_infos.push(self.ncn_config.clone()); account_infos.push(self.restaking_config.clone()); @@ -595,11 +519,8 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { account_infos.push(self.weight_table.clone()); account_infos.push(self.epoch_snapshot.clone()); account_infos.push(self.operator_snapshot.clone()); - account_infos.push(self.vault_operator_delegation_snapshot.clone()); - account_infos.push(self.payer.clone()); account_infos.push(self.vault_program.clone()); account_infos.push(self.restaking_program.clone()); - account_infos.push(self.system_program.clone()); remaining_accounts .iter() .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); @@ -627,11 +548,8 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { /// 8. `[]` weight_table /// 9. `[writable]` epoch_snapshot /// 10. `[writable]` operator_snapshot -/// 11. `[writable]` vault_operator_delegation_snapshot -/// 12. `[writable, signer]` payer -/// 13. `[]` vault_program -/// 14. `[]` restaking_program -/// 15. `[]` system_program +/// 11. `[]` vault_program +/// 12. `[]` restaking_program #[derive(Clone, Debug)] pub struct InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { instruction: Box>, @@ -653,11 +571,8 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { weight_table: None, epoch_snapshot: None, operator_snapshot: None, - vault_operator_delegation_snapshot: None, - payer: None, vault_program: None, restaking_program: None, - system_program: None, first_slot_of_ncn_epoch: None, __remaining_accounts: Vec::new(), }, @@ -747,20 +662,6 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { self } #[inline(always)] - pub fn vault_operator_delegation_snapshot( - &mut self, - vault_operator_delegation_snapshot: &'b solana_program::account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.vault_operator_delegation_snapshot = - Some(vault_operator_delegation_snapshot); - self - } - #[inline(always)] - pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.payer = Some(payer); - self - } - #[inline(always)] pub fn vault_program( &mut self, vault_program: &'b solana_program::account_info::AccountInfo<'a>, @@ -776,14 +677,6 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { self.instruction.restaking_program = Some(restaking_program); self } - #[inline(always)] - pub fn system_program( - &mut self, - system_program: &'b solana_program::account_info::AccountInfo<'a>, - ) -> &mut Self { - self.instruction.system_program = Some(system_program); - self - } /// `[optional argument]` #[inline(always)] pub fn first_slot_of_ncn_epoch(&mut self, first_slot_of_ncn_epoch: u64) -> &mut Self { @@ -880,13 +773,6 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { .operator_snapshot .expect("operator_snapshot is not set"), - vault_operator_delegation_snapshot: self - .instruction - .vault_operator_delegation_snapshot - .expect("vault_operator_delegation_snapshot is not set"), - - payer: self.instruction.payer.expect("payer is not set"), - vault_program: self .instruction .vault_program @@ -896,11 +782,6 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { .instruction .restaking_program .expect("restaking_program is not set"), - - system_program: self - .instruction - .system_program - .expect("system_program is not set"), __args: args, }; instruction.invoke_signed_with_remaining_accounts( @@ -924,11 +805,8 @@ struct InitializeVaultOperatorDelegationSnapshotCpiBuilderInstruction<'a, 'b> { weight_table: Option<&'b solana_program::account_info::AccountInfo<'a>>, epoch_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, operator_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, - vault_operator_delegation_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, - payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, vault_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, restaking_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, - system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, first_slot_of_ncn_epoch: Option, /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. __remaining_accounts: Vec<( diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index bb3a1be..6c31ad5 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -297,6 +297,7 @@ impl OperatorSnapshot { }) } + #[allow(clippy::too_many_arguments)] pub fn new_active( operator: Pubkey, ncn: Pubkey, @@ -501,7 +502,7 @@ impl OperatorSnapshot { let precise_total_security = PreciseNumber::new(total_security as u128) .ok_or(TipRouterError::NewPreciseNumberError)?; - let precise_weight = weight_table.get_precise_weight(&st_mint)?; + let precise_weight = weight_table.get_precise_weight(st_mint)?; let precise_total_votes = precise_total_security .checked_mul(&precise_weight) diff --git a/core/src/instruction.rs b/core/src/instruction.rs index 76f710b..bc439b7 100644 --- a/core/src/instruction.rs +++ b/core/src/instruction.rs @@ -114,11 +114,8 @@ pub enum TipRouterInstruction { #[account(8, name = "weight_table")] #[account(9, writable, name = "epoch_snapshot")] #[account(10, writable, name = "operator_snapshot")] - #[account(11, writable, name = "vault_operator_delegation_snapshot")] - #[account(12, writable, signer, name = "payer")] - #[account(13, name = "vault_program")] - #[account(14, name = "restaking_program")] - #[account(15, name = "system_program")] + #[account(11, name = "vault_program")] + #[account(12, name = "restaking_program")] InitializeVaultOperatorDelegationSnapshot{ first_slot_of_ncn_epoch: Option, }, diff --git a/core/src/weight_table.rs b/core/src/weight_table.rs index 1d907f2..13d5d9e 100644 --- a/core/src/weight_table.rs +++ b/core/src/weight_table.rs @@ -153,7 +153,7 @@ impl WeightTable { } pub fn weight_count(&self) -> usize { - self.table.iter().filter(|entry| !entry.is_set()).count() + self.table.iter().filter(|entry| entry.is_set()).count() } pub const fn ncn(&self) -> Pubkey { diff --git a/idl/jito_tip_router.json b/idl/jito_tip_router.json index 2d574b5..e551af3 100644 --- a/idl/jito_tip_router.json +++ b/idl/jito_tip_router.json @@ -445,16 +445,6 @@ "isMut": true, "isSigner": false }, - { - "name": "vaultOperatorDelegationSnapshot", - "isMut": true, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, { "name": "vaultProgram", "isMut": false, @@ -464,11 +454,6 @@ "name": "restakingProgram", "isMut": false, "isSigner": false - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false } ], "args": [ diff --git a/integration_tests/tests/fixtures/test_builder.rs b/integration_tests/tests/fixtures/test_builder.rs index 8831c93..83f0a21 100644 --- a/integration_tests/tests/fixtures/test_builder.rs +++ b/integration_tests/tests/fixtures/test_builder.rs @@ -1,6 +1,9 @@ use std::fmt::{Debug, Formatter}; -use jito_restaking_core::ncn_vault_ticket::{self, NcnVaultTicket}; +use jito_restaking_core::{ + config::Config, + ncn_vault_ticket::{self, NcnVaultTicket}, +}; use jito_vault_core::vault_ncn_ticket::VaultNcnTicket; use jito_vault_sdk::inline_mpl_token_metadata; use solana_program::{ @@ -216,9 +219,9 @@ impl TestBuilder { let mut vault_program_client = self.vault_program_client(); let mut restaking_program_client = self.restaking_program_client(); - const DEPOSIT_FEE_BPS: u16 = 10; - const WITHDRAWAL_FEE_BPS: u16 = 10; - const REWARD_FEE_BPS: u16 = 10; + const DEPOSIT_FEE_BPS: u16 = 0; + const WITHDRAWAL_FEE_BPS: u16 = 0; + const REWARD_FEE_BPS: u16 = 0; const MINT_AMOUNT: u64 = 1_000_000; for _ in 0..vault_count { @@ -308,13 +311,33 @@ impl TestBuilder { // 5. Setup Tracked Mints pub async fn add_tracked_mints_to_test_ncn(&mut self, test_ncn: &TestNcn) -> TestResult<()> { let mut tip_router_client = self.tip_router_client(); - let mut vault_client = self.vault_program_client(); let mut restaking_client = self.restaking_program_client(); + let mut vault_client = self.vault_program_client(); + + let restaking_config_address = + Config::find_program_address(&jito_restaking_program::id()).0; + let restaking_config = restaking_client + .get_config(&restaking_config_address) + .await?; + + let epoch_length = restaking_config.epoch_length(); + + self.warp_slot_incremental(epoch_length * 2).await.unwrap(); for vault in test_ncn.vaults.iter() { let ncn = test_ncn.ncn_root.ncn_pubkey; let vault = vault.vault_pubkey; + let operators = test_ncn + .operators + .iter() + .map(|operator| operator.operator_pubkey) + .collect::>(); + + vault_client + .do_full_vault_update(&vault, &operators) + .await?; + let vault_ncn_ticket = VaultNcnTicket::find_program_address(&jito_vault_program::id(), &vault, &ncn).0; @@ -328,4 +351,20 @@ impl TestBuilder { Ok(()) } + + pub async fn setup_full_test_ncn( + &mut self, + operator_count: usize, + vault_count: usize, + ) -> TestResult { + let mut test_ncn = self.create_test_ncn().await?; + self.add_operators_to_test_ncn(&mut test_ncn, operator_count) + .await?; + self.add_vaults_to_test_ncn(&mut test_ncn, vault_count) + .await?; + self.add_delegation_in_test_ncn(&test_ncn, 100).await?; + self.add_tracked_mints_to_test_ncn(&test_ncn).await?; + + Ok(test_ncn) + } } diff --git a/integration_tests/tests/fixtures/tip_router_client.rs b/integration_tests/tests/fixtures/tip_router_client.rs index a69e316..3d27afe 100644 --- a/integration_tests/tests/fixtures/tip_router_client.rs +++ b/integration_tests/tests/fixtures/tip_router_client.rs @@ -328,6 +328,7 @@ impl TipRouterClient { .mint(mint) .restaking_program(jito_restaking_program::id()) .weight(weight) + .ncn_epoch(ncn_epoch) .instruction(); let blockhash = self.banks_client.get_latest_blockhash().await?; @@ -496,13 +497,13 @@ impl TipRouterClient { let config_pda = NcnConfig::find_program_address(&jito_tip_router_program::id(), &ncn).0; - let epoch_snapshot = - EpochSnapshot::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; - let ncn_operator_state = NcnOperatorState::find_program_address(&jito_restaking_program::id(), &ncn, &operator) .0; + let epoch_snapshot = + EpochSnapshot::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; + let operator_snapshot = OperatorSnapshot::find_program_address( &jito_tip_router_program::id(), &operator, diff --git a/integration_tests/tests/tip_router/admin_update_weight_table.rs b/integration_tests/tests/tip_router/admin_update_weight_table.rs index adc7d32..252a42b 100644 --- a/integration_tests/tests/tip_router/admin_update_weight_table.rs +++ b/integration_tests/tests/tip_router/admin_update_weight_table.rs @@ -1,34 +1,34 @@ #[cfg(test)] mod tests { - use solana_sdk::pubkey::Pubkey; - use crate::fixtures::{test_builder::TestBuilder, TestResult}; #[tokio::test] async fn test_admin_update_weight_table() -> TestResult<()> { let mut fixture = TestBuilder::new().await; + let mut vault_client = fixture.vault_program_client(); let mut tip_router_client = fixture.tip_router_client(); - let ncn_root = fixture.setup_ncn().await?; + + let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; fixture.warp_slot_incremental(1000).await?; let slot = fixture.clock().await.slot; - tip_router_client.setup_tip_router(&ncn_root).await?; - tip_router_client - .do_initialize_weight_table(ncn_root.ncn_pubkey, slot) + .do_initialize_weight_table(test_ncn.ncn_root.ncn_pubkey, slot) .await?; - let mint = Pubkey::new_unique(); + let vault_root = test_ncn.vaults[0].clone(); + let vault = vault_client.get_vault(&vault_root.vault_pubkey).await?; + + let mint = vault.supported_mint; let weight = 100; tip_router_client - .do_admin_update_weight_table(ncn_root.ncn_pubkey, slot, mint, weight) + .do_admin_update_weight_table(test_ncn.ncn_root.ncn_pubkey, slot, mint, weight) .await?; - //TODO add functionality to update weight table Ok(()) } } diff --git a/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs b/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs index 74708cc..701948e 100644 --- a/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs +++ b/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs @@ -6,26 +6,31 @@ mod tests { #[tokio::test] async fn test_initialize_epoch_snapshot_ok() -> TestResult<()> { let mut fixture = TestBuilder::new().await; + let mut vault_client = fixture.vault_program_client(); let mut tip_router_client = fixture.tip_router_client(); - let ncn_root = fixture.setup_ncn().await?; + + let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; fixture.warp_slot_incremental(1000).await?; let slot = fixture.clock().await.slot; - //TODO fix when config has mints tip_router_client - .do_initialize_config(ncn_root.ncn_pubkey, &ncn_root.ncn_admin) + .do_initialize_weight_table(test_ncn.ncn_root.ncn_pubkey, slot) .await?; + let vault_root = test_ncn.vaults[0].clone(); + let vault = vault_client.get_vault(&vault_root.vault_pubkey).await?; + + let mint = vault.supported_mint; + let weight = 100; + tip_router_client - .do_initialize_weight_table(ncn_root.ncn_pubkey, slot) + .do_admin_update_weight_table(test_ncn.ncn_root.ncn_pubkey, slot, mint, weight) .await?; - //TODO update table - tip_router_client - .do_initialize_epoch_snapshot(ncn_root.ncn_pubkey, slot) + .do_initialize_epoch_snapshot(test_ncn.ncn_root.ncn_pubkey, slot) .await?; Ok(()) diff --git a/integration_tests/tests/tip_router/initialize_operator_snapshot.rs b/integration_tests/tests/tip_router/initialize_operator_snapshot.rs new file mode 100644 index 0000000..ada4375 --- /dev/null +++ b/integration_tests/tests/tip_router/initialize_operator_snapshot.rs @@ -0,0 +1,46 @@ +#[cfg(test)] +mod tests { + + use crate::fixtures::{test_builder::TestBuilder, TestResult}; + + #[tokio::test] + async fn test_initialize_operator_snapshot() -> TestResult<()> { + let mut fixture = TestBuilder::new().await; + let mut vault_client = fixture.vault_program_client(); + let mut tip_router_client = fixture.tip_router_client(); + + let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; + + fixture.warp_slot_incremental(1000).await?; + + let slot = fixture.clock().await.slot; + + tip_router_client + .do_initialize_weight_table(test_ncn.ncn_root.ncn_pubkey, slot) + .await?; + + let ncn = test_ncn.ncn_root.ncn_pubkey; + + let vault_root = test_ncn.vaults[0].clone(); + let vault = vault_client.get_vault(&vault_root.vault_pubkey).await?; + + let mint = vault.supported_mint; + let weight = 100; + + tip_router_client + .do_admin_update_weight_table(ncn, slot, mint, weight) + .await?; + + tip_router_client + .do_initialize_epoch_snapshot(ncn, slot) + .await?; + + let operator = test_ncn.operators[0].operator_pubkey; + + tip_router_client + .do_initalize_operator_snapshot(operator, ncn, slot) + .await?; + + Ok(()) + } +} diff --git a/integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs b/integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs new file mode 100644 index 0000000..2c86fd5 --- /dev/null +++ b/integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs @@ -0,0 +1,51 @@ +#[cfg(test)] +mod tests { + + use crate::fixtures::{test_builder::TestBuilder, TestResult}; + + #[tokio::test] + async fn test_initialize_operator_snapshot() -> TestResult<()> { + let mut fixture = TestBuilder::new().await; + let mut vault_client = fixture.vault_program_client(); + let mut tip_router_client = fixture.tip_router_client(); + + let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; + + fixture.warp_slot_incremental(1000).await?; + + let slot = fixture.clock().await.slot; + + tip_router_client + .do_initialize_weight_table(test_ncn.ncn_root.ncn_pubkey, slot) + .await?; + + let ncn = test_ncn.ncn_root.ncn_pubkey; + + let vault_root = test_ncn.vaults[0].clone(); + let vault_address = vault_root.vault_pubkey; + let vault = vault_client.get_vault(&vault_address).await?; + + let mint = vault.supported_mint; + let weight = 100; + + tip_router_client + .do_admin_update_weight_table(ncn, slot, mint, weight) + .await?; + + tip_router_client + .do_initialize_epoch_snapshot(ncn, slot) + .await?; + + let operator = test_ncn.operators[0].operator_pubkey; + + tip_router_client + .do_initalize_operator_snapshot(operator, ncn, slot) + .await?; + + tip_router_client + .do_initalize_vault_operator_delegation_snapshot(vault_address, operator, ncn, slot) + .await?; + + Ok(()) + } +} diff --git a/integration_tests/tests/tip_router/initialize_weight_table.rs b/integration_tests/tests/tip_router/initialize_weight_table.rs index 3d70c7e..ac13f83 100644 --- a/integration_tests/tests/tip_router/initialize_weight_table.rs +++ b/integration_tests/tests/tip_router/initialize_weight_table.rs @@ -7,17 +7,17 @@ mod tests { async fn test_initialize_weight_table_ok() -> TestResult<()> { let mut fixture = TestBuilder::new().await; let mut tip_router_client = fixture.tip_router_client(); - let ncn_root = fixture.setup_ncn().await?; + + let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; fixture.warp_slot_incremental(1000).await?; let slot = fixture.clock().await.slot; - tip_router_client.setup_tip_router(&ncn_root).await?; - tip_router_client - .do_initialize_weight_table(ncn_root.ncn_pubkey, slot) + .do_initialize_weight_table(test_ncn.ncn_root.ncn_pubkey, slot) .await?; + Ok(()) } } diff --git a/integration_tests/tests/tip_router/mod.rs b/integration_tests/tests/tip_router/mod.rs index 29c7398..b12d6c8 100644 --- a/integration_tests/tests/tip_router/mod.rs +++ b/integration_tests/tests/tip_router/mod.rs @@ -1,7 +1,9 @@ mod admin_update_weight_table; mod initialize_epoch_snapshot; mod initialize_ncn_config; +mod initialize_operator_snapshot; mod initialize_tracked_mints; +mod initialize_vault_operator_delegation_snapshot; mod initialize_weight_table; mod register_mint; mod set_config_fees; diff --git a/program/src/initialize_operator_snapshot.rs b/program/src/initialize_operator_snapshot.rs index f339ff0..e1b6df7 100644 --- a/program/src/initialize_operator_snapshot.rs +++ b/program/src/initialize_operator_snapshot.rs @@ -45,7 +45,7 @@ pub fn process_initialize_operator_snapshot( false, )?; - load_system_account(epoch_snapshot, true)?; + load_system_account(operator_snapshot, true)?; load_system_program(system_program)?; //TODO check that it is not writable load_signer(payer, false)?; @@ -57,7 +57,7 @@ pub fn process_initialize_operator_snapshot( EpochSnapshot::load(program_id, ncn.key, ncn_epoch, epoch_snapshot, true)?; let (operator_snapshot_pubkey, operator_snapshot_bump, mut operator_snapshot_seeds) = - EpochSnapshot::find_program_address(program_id, ncn.key, ncn_epoch); + OperatorSnapshot::find_program_address(program_id, operator.key, ncn.key, ncn_epoch); operator_snapshot_seeds.push(vec![operator_snapshot_bump]); if operator_snapshot_pubkey.ne(operator_snapshot.key) { diff --git a/program/src/initialize_vault_operator_delegation_snapshot.rs b/program/src/initialize_vault_operator_delegation_snapshot.rs index b7fe402..2d1bcb3 100644 --- a/program/src/initialize_vault_operator_delegation_snapshot.rs +++ b/program/src/initialize_vault_operator_delegation_snapshot.rs @@ -22,7 +22,6 @@ pub fn process_initialize_vault_operator_delegation_snapshot( accounts: &[AccountInfo], first_slot_of_ncn_epoch: Option, ) -> ProgramResult { - //TODO remove payer, system_program, and vault_operator_delegation_snapshot let [ncn_config, restaking_config, ncn, operator, vault, vault_ncn_ticket, ncn_vault_ticket, vault_operator_delegation, weight_table, epoch_snapshot, operator_snapshot, vault_program, restaking_program] = accounts else { @@ -60,7 +59,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( //TODO what happens if a new Vault is added inbetween weight table creation and this? - There could be a count mismatch if !vault_operator_delegation.data_is_empty() { VaultOperatorDelegation::load( - restaking_program.key, + vault_program.key, vault_operator_delegation, vault, operator, @@ -79,7 +78,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( operator.key, ncn.key, ncn_epoch, - epoch_snapshot, + operator_snapshot, true, )?; @@ -119,13 +118,11 @@ pub fn process_initialize_vault_operator_delegation_snapshot( let weight_table_data = weight_table.data.borrow(); let weight_table_account = WeightTable::try_from_slice_unchecked(&weight_table_data)?; - let total_votes = OperatorSnapshot::calculate_total_votes( - &vault_operator_delegation_account, - &weight_table_account, + OperatorSnapshot::calculate_total_votes( + vault_operator_delegation_account, + weight_table_account, &st_mint, - )?; - - total_votes + )? } else { 0u128 }; From 9df99c3ec2ce10e71993a62efda6343886714956 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Fri, 15 Nov 2024 14:09:06 -0800 Subject: [PATCH 19/28] working --- .../tests/fixtures/restaking_client.rs | 7 ++ .../tests/fixtures/test_builder.rs | 100 ++++++++++++++++- .../tests/fixtures/tip_router_client.rs | 52 +++++++++ .../tip_router/admin_update_weight_table.rs | 2 +- .../tip_router/initialize_epoch_snapshot.rs | 2 +- .../initialize_operator_snapshot.rs | 2 +- ...lize_vault_operator_delegation_snapshot.rs | 2 +- .../tip_router/initialize_weight_table.rs | 2 +- .../tests/tip_router/meta_tests.rs | 105 ++++++++++++++++++ integration_tests/tests/tip_router/mod.rs | 1 + 10 files changed, 269 insertions(+), 6 deletions(-) create mode 100644 integration_tests/tests/tip_router/meta_tests.rs diff --git a/integration_tests/tests/fixtures/restaking_client.rs b/integration_tests/tests/fixtures/restaking_client.rs index 4ebed7d..186daa9 100644 --- a/integration_tests/tests/fixtures/restaking_client.rs +++ b/integration_tests/tests/fixtures/restaking_client.rs @@ -88,6 +88,13 @@ impl RestakingProgramClient { Ok(*Config::try_from_slice_unchecked(account.data.as_slice())?) } + pub async fn get_ncn_epoch(&mut self, slot: u64) -> TestResult { + let restaking_config_address = + Config::find_program_address(&jito_restaking_program::id()).0; + let config = self.get_config(&restaking_config_address).await.unwrap(); + Ok(config.get_epoch_from_slot(slot).unwrap()) + } + pub async fn get_ncn_vault_ticket( &mut self, ncn: &Pubkey, diff --git a/integration_tests/tests/fixtures/test_builder.rs b/integration_tests/tests/fixtures/test_builder.rs index 83f0a21..35cde4e 100644 --- a/integration_tests/tests/fixtures/test_builder.rs +++ b/integration_tests/tests/fixtures/test_builder.rs @@ -352,7 +352,8 @@ impl TestBuilder { Ok(()) } - pub async fn setup_full_test_ncn( + // Intermission: setup just NCN + pub async fn create_initial_test_ncn( &mut self, operator_count: usize, vault_count: usize, @@ -367,4 +368,101 @@ impl TestBuilder { Ok(test_ncn) } + + // 6. Set weights + pub async fn add_weights_for_test_ncn(&mut self, test_ncn: &TestNcn) -> TestResult<()> { + let mut tip_router_client = self.tip_router_client(); + let mut vault_client = self.vault_program_client(); + + const WEIGHT: u128 = 100; + + // Not sure if this is needed + self.warp_slot_incremental(1000).await?; + + let slot = self.clock().await.slot; + tip_router_client + .do_initialize_weight_table(test_ncn.ncn_root.ncn_pubkey, slot) + .await?; + + for vault_root in test_ncn.vaults.iter() { + let vault = vault_client.get_vault(&vault_root.vault_pubkey).await?; + + let mint = vault.supported_mint; + + tip_router_client + .do_admin_update_weight_table(test_ncn.ncn_root.ncn_pubkey, slot, mint, WEIGHT) + .await?; + } + + Ok(()) + } + + // 7. Create Epoch Snapshot + pub async fn add_epoch_snapshot_to_test_ncn(&mut self, test_ncn: &TestNcn) -> TestResult<()> { + let mut tip_router_client = self.tip_router_client(); + + let slot = self.clock().await.slot; + + tip_router_client + .do_initialize_epoch_snapshot(test_ncn.ncn_root.ncn_pubkey, slot) + .await?; + + Ok(()) + } + + // 8. Create all operator snapshots + pub async fn add_operator_snapshots_to_test_ncn( + &mut self, + test_ncn: &TestNcn, + ) -> TestResult<()> { + let mut tip_router_client = self.tip_router_client(); + + let slot = self.clock().await.slot; + let ncn = test_ncn.ncn_root.ncn_pubkey; + + for operator_root in test_ncn.operators.iter() { + let operator = operator_root.operator_pubkey; + + tip_router_client + .do_initalize_operator_snapshot(operator, ncn, slot) + .await?; + } + + Ok(()) + } + + // 9. Take all VaultOperatorDelegation snapshots + pub async fn add_vault_operator_delegation_snapshots_to_test_ncn( + &mut self, + test_ncn: &TestNcn, + ) -> TestResult<()> { + let mut tip_router_client = self.tip_router_client(); + + let slot = self.clock().await.slot; + let ncn = test_ncn.ncn_root.ncn_pubkey; + + for operator_root in test_ncn.operators.iter() { + let operator = operator_root.operator_pubkey; + for vault_root in test_ncn.vaults.iter() { + let vault = vault_root.vault_pubkey; + + tip_router_client + .do_initalize_vault_operator_delegation_snapshot(vault, operator, ncn, slot) + .await?; + } + } + + Ok(()) + } + + // Intermission 2 - all snapshots are taken + pub async fn snapshot_test_ncn(&mut self, test_ncn: &TestNcn) -> TestResult<()> { + self.add_weights_for_test_ncn(&test_ncn).await?; + self.add_epoch_snapshot_to_test_ncn(&test_ncn).await?; + self.add_operator_snapshots_to_test_ncn(&test_ncn).await?; + self.add_vault_operator_delegation_snapshots_to_test_ncn(&test_ncn) + .await?; + + Ok(()) + } } diff --git a/integration_tests/tests/fixtures/tip_router_client.rs b/integration_tests/tests/fixtures/tip_router_client.rs index 3d27afe..86f8c5e 100644 --- a/integration_tests/tests/fixtures/tip_router_client.rs +++ b/integration_tests/tests/fixtures/tip_router_client.rs @@ -112,6 +112,58 @@ impl TipRouterClient { Ok(*TrackedMints::try_from_slice_unchecked(tracked_mints.data.as_slice()).unwrap()) } + pub async fn get_weight_table( + &mut self, + ncn: Pubkey, + ncn_epoch: u64, + ) -> TestResult { + let address = + WeightTable::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; + + let raw_account = self.banks_client.get_account(address).await?.unwrap(); + + let account = WeightTable::try_from_slice_unchecked(raw_account.data.as_slice()).unwrap(); + + Ok(*account) + } + + pub async fn get_epoch_snapshot( + &mut self, + ncn: Pubkey, + ncn_epoch: u64, + ) -> TestResult { + let address = + EpochSnapshot::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; + + let raw_account = self.banks_client.get_account(address).await?.unwrap(); + + let account = EpochSnapshot::try_from_slice_unchecked(raw_account.data.as_slice()).unwrap(); + + Ok(*account) + } + + pub async fn get_operator_snapshot( + &mut self, + operator: Pubkey, + ncn: Pubkey, + ncn_epoch: u64, + ) -> TestResult { + let address = OperatorSnapshot::find_program_address( + &jito_tip_router_program::id(), + &operator, + &ncn, + ncn_epoch, + ) + .0; + + let raw_account = self.banks_client.get_account(address).await?.unwrap(); + + let account = + OperatorSnapshot::try_from_slice_unchecked(raw_account.data.as_slice()).unwrap(); + + Ok(*account) + } + pub async fn do_initialize_config( &mut self, ncn: Pubkey, diff --git a/integration_tests/tests/tip_router/admin_update_weight_table.rs b/integration_tests/tests/tip_router/admin_update_weight_table.rs index 252a42b..58897d2 100644 --- a/integration_tests/tests/tip_router/admin_update_weight_table.rs +++ b/integration_tests/tests/tip_router/admin_update_weight_table.rs @@ -9,7 +9,7 @@ mod tests { let mut vault_client = fixture.vault_program_client(); let mut tip_router_client = fixture.tip_router_client(); - let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; + let test_ncn = fixture.create_initial_test_ncn(1, 1).await?; fixture.warp_slot_incremental(1000).await?; diff --git a/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs b/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs index 701948e..706e7b5 100644 --- a/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs +++ b/integration_tests/tests/tip_router/initialize_epoch_snapshot.rs @@ -9,7 +9,7 @@ mod tests { let mut vault_client = fixture.vault_program_client(); let mut tip_router_client = fixture.tip_router_client(); - let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; + let test_ncn = fixture.create_initial_test_ncn(1, 1).await?; fixture.warp_slot_incremental(1000).await?; diff --git a/integration_tests/tests/tip_router/initialize_operator_snapshot.rs b/integration_tests/tests/tip_router/initialize_operator_snapshot.rs index ada4375..0c1f202 100644 --- a/integration_tests/tests/tip_router/initialize_operator_snapshot.rs +++ b/integration_tests/tests/tip_router/initialize_operator_snapshot.rs @@ -9,7 +9,7 @@ mod tests { let mut vault_client = fixture.vault_program_client(); let mut tip_router_client = fixture.tip_router_client(); - let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; + let test_ncn = fixture.create_initial_test_ncn(1, 1).await?; fixture.warp_slot_incremental(1000).await?; diff --git a/integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs b/integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs index 2c86fd5..d7c1475 100644 --- a/integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs +++ b/integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs @@ -9,7 +9,7 @@ mod tests { let mut vault_client = fixture.vault_program_client(); let mut tip_router_client = fixture.tip_router_client(); - let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; + let test_ncn = fixture.create_initial_test_ncn(1, 1).await?; fixture.warp_slot_incremental(1000).await?; diff --git a/integration_tests/tests/tip_router/initialize_weight_table.rs b/integration_tests/tests/tip_router/initialize_weight_table.rs index ac13f83..62a8d00 100644 --- a/integration_tests/tests/tip_router/initialize_weight_table.rs +++ b/integration_tests/tests/tip_router/initialize_weight_table.rs @@ -8,7 +8,7 @@ mod tests { let mut fixture = TestBuilder::new().await; let mut tip_router_client = fixture.tip_router_client(); - let test_ncn = fixture.setup_full_test_ncn(1, 1).await?; + let test_ncn = fixture.create_initial_test_ncn(1, 1).await?; fixture.warp_slot_incremental(1000).await?; diff --git a/integration_tests/tests/tip_router/meta_tests.rs b/integration_tests/tests/tip_router/meta_tests.rs new file mode 100644 index 0000000..0328ecf --- /dev/null +++ b/integration_tests/tests/tip_router/meta_tests.rs @@ -0,0 +1,105 @@ +#[cfg(test)] +mod tests { + + use crate::fixtures::{ + restaking_client, test_builder::TestBuilder, tip_router_client, TestResult, + }; + + #[tokio::test] + async fn test_all_test_ncn_functions() -> TestResult<()> { + let mut fixture = TestBuilder::new().await; + + const OPERATOR_COUNT: usize = 1; + const VAULT_COUNT: usize = 1; + + let mut test_ncn = fixture.create_test_ncn().await?; + fixture + .add_operators_to_test_ncn(&mut test_ncn, OPERATOR_COUNT) + .await?; + fixture + .add_vaults_to_test_ncn(&mut test_ncn, VAULT_COUNT) + .await?; + fixture.add_delegation_in_test_ncn(&test_ncn, 100).await?; + fixture.add_tracked_mints_to_test_ncn(&test_ncn).await?; + fixture.add_weights_for_test_ncn(&test_ncn).await?; + fixture.add_epoch_snapshot_to_test_ncn(&test_ncn).await?; + fixture + .add_operator_snapshots_to_test_ncn(&test_ncn) + .await?; + fixture + .add_vault_operator_delegation_snapshots_to_test_ncn(&test_ncn) + .await?; + + Ok(()) + } + + #[tokio::test] + async fn test_intermission_test_ncn_functions() -> TestResult<()> { + let mut fixture = TestBuilder::new().await; + let mut tip_router_client = fixture.tip_router_client(); + + const OPERATOR_COUNT: usize = 1; + const VAULT_COUNT: usize = 1; + + let test_ncn = fixture + .create_initial_test_ncn(OPERATOR_COUNT, VAULT_COUNT) + .await?; + fixture.snapshot_test_ncn(&test_ncn).await?; + + Ok(()) + } + + #[tokio::test] + async fn test_multiple_operators() -> TestResult<()> { + let mut fixture = TestBuilder::new().await; + let mut tip_router_client = fixture.tip_router_client(); + let mut restaking_client = fixture.restaking_program_client(); + + const OPERATOR_COUNT: usize = 10; + const VAULT_COUNT: usize = 1; + + let test_ncn = fixture + .create_initial_test_ncn(OPERATOR_COUNT, VAULT_COUNT) + .await?; + fixture.snapshot_test_ncn(&test_ncn).await?; + + let slot = fixture.clock().await.slot; + let ncn_epoch = restaking_client.get_ncn_epoch(slot).await?; + + let epoch_snapshot = tip_router_client + .get_epoch_snapshot(test_ncn.ncn_root.ncn_pubkey, ncn_epoch) + .await?; + + Ok(()) + } + + #[tokio::test] + async fn test_multiple_vaults() -> TestResult<()> { + let mut fixture = TestBuilder::new().await; + + const OPERATOR_COUNT: usize = 1; + const VAULT_COUNT: usize = 10; + + let test_ncn = fixture + .create_initial_test_ncn(OPERATOR_COUNT, VAULT_COUNT) + .await?; + fixture.snapshot_test_ncn(&test_ncn).await?; + + Ok(()) + } + + #[tokio::test] + async fn test_multiple_operators_and_vaults() -> TestResult<()> { + let mut fixture = TestBuilder::new().await; + + const OPERATOR_COUNT: usize = 10; + const VAULT_COUNT: usize = 10; + + let test_ncn = fixture + .create_initial_test_ncn(OPERATOR_COUNT, VAULT_COUNT) + .await?; + fixture.snapshot_test_ncn(&test_ncn).await?; + + Ok(()) + } +} diff --git a/integration_tests/tests/tip_router/mod.rs b/integration_tests/tests/tip_router/mod.rs index b12d6c8..99b6f14 100644 --- a/integration_tests/tests/tip_router/mod.rs +++ b/integration_tests/tests/tip_router/mod.rs @@ -5,6 +5,7 @@ mod initialize_operator_snapshot; mod initialize_tracked_mints; mod initialize_vault_operator_delegation_snapshot; mod initialize_weight_table; +mod meta_tests; mod register_mint; mod set_config_fees; mod set_new_admin; From 919c96acac68bba4e89f222a04180cefe5e20971 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Fri, 15 Nov 2024 14:26:33 -0800 Subject: [PATCH 20/28] test made --- integration_tests/tests/tip_router/meta_tests.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integration_tests/tests/tip_router/meta_tests.rs b/integration_tests/tests/tip_router/meta_tests.rs index 0328ecf..7840b66 100644 --- a/integration_tests/tests/tip_router/meta_tests.rs +++ b/integration_tests/tests/tip_router/meta_tests.rs @@ -70,6 +70,8 @@ mod tests { .get_epoch_snapshot(test_ncn.ncn_root.ncn_pubkey, ncn_epoch) .await?; + assert!(epoch_snapshot.finalized()); + Ok(()) } From ab9015e7d3eab1298f37772c7911d39c6b60d92a Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Fri, 15 Nov 2024 14:29:19 -0800 Subject: [PATCH 21/28] test are intermittent --- .../tests/tip_router/meta_tests.rs | 36 +++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/integration_tests/tests/tip_router/meta_tests.rs b/integration_tests/tests/tip_router/meta_tests.rs index 7840b66..2cc4ee8 100644 --- a/integration_tests/tests/tip_router/meta_tests.rs +++ b/integration_tests/tests/tip_router/meta_tests.rs @@ -1,9 +1,7 @@ #[cfg(test)] mod tests { - use crate::fixtures::{ - restaking_client, test_builder::TestBuilder, tip_router_client, TestResult, - }; + use crate::fixtures::{test_builder::TestBuilder, TestResult}; #[tokio::test] async fn test_all_test_ncn_functions() -> TestResult<()> { @@ -37,6 +35,7 @@ mod tests { async fn test_intermission_test_ncn_functions() -> TestResult<()> { let mut fixture = TestBuilder::new().await; let mut tip_router_client = fixture.tip_router_client(); + let mut restaking_client = fixture.restaking_program_client(); const OPERATOR_COUNT: usize = 1; const VAULT_COUNT: usize = 1; @@ -46,6 +45,15 @@ mod tests { .await?; fixture.snapshot_test_ncn(&test_ncn).await?; + let slot = fixture.clock().await.slot; + let ncn_epoch = restaking_client.get_ncn_epoch(slot).await?; + + let epoch_snapshot = tip_router_client + .get_epoch_snapshot(test_ncn.ncn_root.ncn_pubkey, ncn_epoch) + .await?; + + assert!(epoch_snapshot.finalized()); + Ok(()) } @@ -78,6 +86,8 @@ mod tests { #[tokio::test] async fn test_multiple_vaults() -> TestResult<()> { let mut fixture = TestBuilder::new().await; + let mut tip_router_client = fixture.tip_router_client(); + let mut restaking_client = fixture.restaking_program_client(); const OPERATOR_COUNT: usize = 1; const VAULT_COUNT: usize = 10; @@ -87,12 +97,23 @@ mod tests { .await?; fixture.snapshot_test_ncn(&test_ncn).await?; + let slot = fixture.clock().await.slot; + let ncn_epoch = restaking_client.get_ncn_epoch(slot).await?; + + let epoch_snapshot = tip_router_client + .get_epoch_snapshot(test_ncn.ncn_root.ncn_pubkey, ncn_epoch) + .await?; + + assert!(epoch_snapshot.finalized()); + Ok(()) } #[tokio::test] async fn test_multiple_operators_and_vaults() -> TestResult<()> { let mut fixture = TestBuilder::new().await; + let mut tip_router_client = fixture.tip_router_client(); + let mut restaking_client = fixture.restaking_program_client(); const OPERATOR_COUNT: usize = 10; const VAULT_COUNT: usize = 10; @@ -102,6 +123,15 @@ mod tests { .await?; fixture.snapshot_test_ncn(&test_ncn).await?; + let slot = fixture.clock().await.slot; + let ncn_epoch = restaking_client.get_ncn_epoch(slot).await?; + + let epoch_snapshot = tip_router_client + .get_epoch_snapshot(test_ncn.ncn_root.ncn_pubkey, ncn_epoch) + .await?; + + assert!(epoch_snapshot.finalized()); + Ok(()) } } From a748cb15716ce7c1fbddf49023008fc0414b08bd Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Tue, 19 Nov 2024 10:16:45 -0600 Subject: [PATCH 22/28] looking better --- .../jito_tip_router/accounts/epochSnapshot.ts | 12 ++- .../accounts/operatorSnapshot.ts | 28 ++--- .../js/jito_tip_router/instructions/index.ts | 2 +- .../instructions/initializeEpochSnapshot.ts | 26 +++-- ....ts => snapshotVaultOperatorDelegation.ts} | 58 +++++----- .../jito_tip_router/programs/jitoTipRouter.ts | 10 +- clients/js/jito_tip_router/types/index.ts | 2 +- ...orVotes.ts => vaultOperatorStakeWeight.ts} | 26 ++--- .../src/generated/accounts/epoch_snapshot.rs | 3 +- .../generated/accounts/operator_snapshot.rs | 7 +- .../instructions/initialize_epoch_snapshot.rs | 66 +++++++++--- .../src/generated/instructions/mod.rs | 6 +- ... => snapshot_vault_operator_delegation.rs} | 98 +++++++++-------- .../src/generated/types/mod.rs | 4 +- ...otes.rs => vault_operator_stake_weight.rs} | 4 +- core/src/epoch_snapshot.rs | 101 ++++++++++-------- core/src/instruction.rs | 13 +-- idl/jito_tip_router.json | 27 +++-- .../tests/fixtures/test_builder.rs | 2 +- .../tests/fixtures/tip_router_client.rs | 17 +-- integration_tests/tests/tip_router/mod.rs | 2 +- ... => snapshot_vault_operator_delegation.rs} | 2 +- program/src/initialize_epoch_snapshot.rs | 12 ++- program/src/initialize_operator_snapshot.rs | 9 +- program/src/lib.rs | 8 +- ... => snapshot_vault_operator_delegation.rs} | 11 +- 26 files changed, 321 insertions(+), 235 deletions(-) rename clients/js/jito_tip_router/instructions/{initializeVaultOperatorDelegationSnapshot.ts => snapshotVaultOperatorDelegation.ts} (84%) rename clients/js/jito_tip_router/types/{vaultOperatorVotes.ts => vaultOperatorStakeWeight.ts} (64%) rename clients/rust/jito_tip_router/src/generated/instructions/{initialize_vault_operator_delegation_snapshot.rs => snapshot_vault_operator_delegation.rs} (90%) rename clients/rust/jito_tip_router/src/generated/types/{vault_operator_votes.rs => vault_operator_stake_weight.rs} (90%) rename integration_tests/tests/tip_router/{initialize_vault_operator_delegation_snapshot.rs => snapshot_vault_operator_delegation.rs} (93%) rename program/src/{initialize_vault_operator_delegation_snapshot.rs => snapshot_vault_operator_delegation.rs} (92%) diff --git a/clients/js/jito_tip_router/accounts/epochSnapshot.ts b/clients/js/jito_tip_router/accounts/epochSnapshot.ts index 86bfa4c..18dcef0 100644 --- a/clients/js/jito_tip_router/accounts/epochSnapshot.ts +++ b/clients/js/jito_tip_router/accounts/epochSnapshot.ts @@ -52,9 +52,10 @@ export type EpochSnapshot = { slotFinalized: bigint; ncnFees: Fees; operatorCount: bigint; + vaultCount: bigint; operatorsRegistered: bigint; validOperatorVaultDelegations: bigint; - totalVotes: bigint; + stakeWeight: bigint; reserved: Array; }; @@ -67,9 +68,10 @@ export type EpochSnapshotArgs = { slotFinalized: number | bigint; ncnFees: FeesArgs; operatorCount: number | bigint; + vaultCount: number | bigint; operatorsRegistered: number | bigint; validOperatorVaultDelegations: number | bigint; - totalVotes: number | bigint; + stakeWeight: number | bigint; reserved: Array; }; @@ -83,9 +85,10 @@ export function getEpochSnapshotEncoder(): Encoder { ['slotFinalized', getU64Encoder()], ['ncnFees', getFeesEncoder()], ['operatorCount', getU64Encoder()], + ['vaultCount', getU64Encoder()], ['operatorsRegistered', getU64Encoder()], ['validOperatorVaultDelegations', getU64Encoder()], - ['totalVotes', getU128Encoder()], + ['stakeWeight', getU128Encoder()], ['reserved', getArrayEncoder(getU8Encoder(), { size: 128 })], ]); } @@ -100,9 +103,10 @@ export function getEpochSnapshotDecoder(): Decoder { ['slotFinalized', getU64Decoder()], ['ncnFees', getFeesDecoder()], ['operatorCount', getU64Decoder()], + ['vaultCount', getU64Decoder()], ['operatorsRegistered', getU64Decoder()], ['validOperatorVaultDelegations', getU64Decoder()], - ['totalVotes', getU128Decoder()], + ['stakeWeight', getU128Decoder()], ['reserved', getArrayDecoder(getU8Decoder(), { size: 128 })], ]); } diff --git a/clients/js/jito_tip_router/accounts/operatorSnapshot.ts b/clients/js/jito_tip_router/accounts/operatorSnapshot.ts index d8c0696..32b0633 100644 --- a/clients/js/jito_tip_router/accounts/operatorSnapshot.ts +++ b/clients/js/jito_tip_router/accounts/operatorSnapshot.ts @@ -41,10 +41,10 @@ import { type MaybeEncodedAccount, } from '@solana/web3.js'; import { - getVaultOperatorVotesDecoder, - getVaultOperatorVotesEncoder, - type VaultOperatorVotes, - type VaultOperatorVotesArgs, + getVaultOperatorStakeWeightDecoder, + getVaultOperatorStakeWeightEncoder, + type VaultOperatorStakeWeight, + type VaultOperatorStakeWeightArgs, } from '../types'; export type OperatorSnapshot = { @@ -61,9 +61,9 @@ export type OperatorSnapshot = { vaultOperatorDelegationCount: bigint; vaultOperatorDelegationsRegistered: bigint; validOperatorVaultDelegations: bigint; - totalVotes: bigint; + stakeWeight: bigint; reserved: Array; - vaultOperatorVotes: Array; + vaultOperatorStakeWeight: Array; }; export type OperatorSnapshotArgs = { @@ -80,9 +80,9 @@ export type OperatorSnapshotArgs = { vaultOperatorDelegationCount: number | bigint; vaultOperatorDelegationsRegistered: number | bigint; validOperatorVaultDelegations: number | bigint; - totalVotes: number | bigint; + stakeWeight: number | bigint; reserved: Array; - vaultOperatorVotes: Array; + vaultOperatorStakeWeight: Array; }; export function getOperatorSnapshotEncoder(): Encoder { @@ -100,11 +100,11 @@ export function getOperatorSnapshotEncoder(): Encoder { ['vaultOperatorDelegationCount', getU64Encoder()], ['vaultOperatorDelegationsRegistered', getU64Encoder()], ['validOperatorVaultDelegations', getU64Encoder()], - ['totalVotes', getU128Encoder()], + ['stakeWeight', getU128Encoder()], ['reserved', getArrayEncoder(getU8Encoder(), { size: 256 })], [ - 'vaultOperatorVotes', - getArrayEncoder(getVaultOperatorVotesEncoder(), { size: 64 }), + 'vaultOperatorStakeWeight', + getArrayEncoder(getVaultOperatorStakeWeightEncoder(), { size: 32 }), ], ]); } @@ -124,11 +124,11 @@ export function getOperatorSnapshotDecoder(): Decoder { ['vaultOperatorDelegationCount', getU64Decoder()], ['vaultOperatorDelegationsRegistered', getU64Decoder()], ['validOperatorVaultDelegations', getU64Decoder()], - ['totalVotes', getU128Decoder()], + ['stakeWeight', getU128Decoder()], ['reserved', getArrayDecoder(getU8Decoder(), { size: 256 })], [ - 'vaultOperatorVotes', - getArrayDecoder(getVaultOperatorVotesDecoder(), { size: 64 }), + 'vaultOperatorStakeWeight', + getArrayDecoder(getVaultOperatorStakeWeightDecoder(), { size: 32 }), ], ]); } diff --git a/clients/js/jito_tip_router/instructions/index.ts b/clients/js/jito_tip_router/instructions/index.ts index 4a87226..5771c79 100644 --- a/clients/js/jito_tip_router/instructions/index.ts +++ b/clients/js/jito_tip_router/instructions/index.ts @@ -11,8 +11,8 @@ export * from './initializeEpochSnapshot'; export * from './initializeNCNConfig'; export * from './initializeOperatorSnapshot'; export * from './initializeTrackedMints'; -export * from './initializeVaultOperatorDelegationSnapshot'; export * from './initializeWeightTable'; export * from './registerMint'; export * from './setConfigFees'; export * from './setNewAdmin'; +export * from './snapshotVaultOperatorDelegation'; diff --git a/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts b/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts index 66cb8f9..a011b9c 100644 --- a/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts +++ b/clients/js/jito_tip_router/instructions/initializeEpochSnapshot.ts @@ -47,6 +47,7 @@ export type InitializeEpochSnapshotInstruction< TAccountNcnConfig extends string | IAccountMeta = string, TAccountRestakingConfig extends string | IAccountMeta = string, TAccountNcn extends string | IAccountMeta = string, + TAccountTrackedMints extends string | IAccountMeta = string, TAccountWeightTable extends string | IAccountMeta = string, TAccountEpochSnapshot extends string | IAccountMeta = string, TAccountPayer extends string | IAccountMeta = string, @@ -66,6 +67,9 @@ export type InitializeEpochSnapshotInstruction< ? ReadonlyAccount : TAccountRestakingConfig, TAccountNcn extends string ? ReadonlyAccount : TAccountNcn, + TAccountTrackedMints extends string + ? ReadonlyAccount + : TAccountTrackedMints, TAccountWeightTable extends string ? ReadonlyAccount : TAccountWeightTable, @@ -129,6 +133,7 @@ export type InitializeEpochSnapshotInput< TAccountNcnConfig extends string = string, TAccountRestakingConfig extends string = string, TAccountNcn extends string = string, + TAccountTrackedMints extends string = string, TAccountWeightTable extends string = string, TAccountEpochSnapshot extends string = string, TAccountPayer extends string = string, @@ -138,6 +143,7 @@ export type InitializeEpochSnapshotInput< ncnConfig: Address; restakingConfig: Address; ncn: Address; + trackedMints: Address; weightTable: Address; epochSnapshot: Address; payer: TransactionSigner; @@ -150,6 +156,7 @@ export function getInitializeEpochSnapshotInstruction< TAccountNcnConfig extends string, TAccountRestakingConfig extends string, TAccountNcn extends string, + TAccountTrackedMints extends string, TAccountWeightTable extends string, TAccountEpochSnapshot extends string, TAccountPayer extends string, @@ -161,6 +168,7 @@ export function getInitializeEpochSnapshotInstruction< TAccountNcnConfig, TAccountRestakingConfig, TAccountNcn, + TAccountTrackedMints, TAccountWeightTable, TAccountEpochSnapshot, TAccountPayer, @@ -173,6 +181,7 @@ export function getInitializeEpochSnapshotInstruction< TAccountNcnConfig, TAccountRestakingConfig, TAccountNcn, + TAccountTrackedMints, TAccountWeightTable, TAccountEpochSnapshot, TAccountPayer, @@ -191,6 +200,7 @@ export function getInitializeEpochSnapshotInstruction< isWritable: false, }, ncn: { value: input.ncn ?? null, isWritable: false }, + trackedMints: { value: input.trackedMints ?? null, isWritable: false }, weightTable: { value: input.weightTable ?? null, isWritable: false }, epochSnapshot: { value: input.epochSnapshot ?? null, isWritable: true }, payer: { value: input.payer ?? null, isWritable: true }, @@ -220,6 +230,7 @@ export function getInitializeEpochSnapshotInstruction< getAccountMeta(accounts.ncnConfig), getAccountMeta(accounts.restakingConfig), getAccountMeta(accounts.ncn), + getAccountMeta(accounts.trackedMints), getAccountMeta(accounts.weightTable), getAccountMeta(accounts.epochSnapshot), getAccountMeta(accounts.payer), @@ -235,6 +246,7 @@ export function getInitializeEpochSnapshotInstruction< TAccountNcnConfig, TAccountRestakingConfig, TAccountNcn, + TAccountTrackedMints, TAccountWeightTable, TAccountEpochSnapshot, TAccountPayer, @@ -254,11 +266,12 @@ export type ParsedInitializeEpochSnapshotInstruction< ncnConfig: TAccountMetas[0]; restakingConfig: TAccountMetas[1]; ncn: TAccountMetas[2]; - weightTable: TAccountMetas[3]; - epochSnapshot: TAccountMetas[4]; - payer: TAccountMetas[5]; - restakingProgram: TAccountMetas[6]; - systemProgram: TAccountMetas[7]; + trackedMints: TAccountMetas[3]; + weightTable: TAccountMetas[4]; + epochSnapshot: TAccountMetas[5]; + payer: TAccountMetas[6]; + restakingProgram: TAccountMetas[7]; + systemProgram: TAccountMetas[8]; }; data: InitializeEpochSnapshotInstructionData; }; @@ -271,7 +284,7 @@ export function parseInitializeEpochSnapshotInstruction< IInstructionWithAccounts & IInstructionWithData ): ParsedInitializeEpochSnapshotInstruction { - if (instruction.accounts.length < 8) { + if (instruction.accounts.length < 9) { // TODO: Coded error. throw new Error('Not enough accounts'); } @@ -287,6 +300,7 @@ export function parseInitializeEpochSnapshotInstruction< ncnConfig: getNextAccount(), restakingConfig: getNextAccount(), ncn: getNextAccount(), + trackedMints: getNextAccount(), weightTable: getNextAccount(), epochSnapshot: getNextAccount(), payer: getNextAccount(), diff --git a/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts b/clients/js/jito_tip_router/instructions/snapshotVaultOperatorDelegation.ts similarity index 84% rename from clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts rename to clients/js/jito_tip_router/instructions/snapshotVaultOperatorDelegation.ts index 35b5b5b..17fbe18 100644 --- a/clients/js/jito_tip_router/instructions/initializeVaultOperatorDelegationSnapshot.ts +++ b/clients/js/jito_tip_router/instructions/snapshotVaultOperatorDelegation.ts @@ -33,15 +33,15 @@ import { import { JITO_TIP_ROUTER_PROGRAM_ADDRESS } from '../programs'; import { getAccountMetaFactory, type ResolvedAccount } from '../shared'; -export const INITIALIZE_VAULT_OPERATOR_DELEGATION_SNAPSHOT_DISCRIMINATOR = 7; +export const SNAPSHOT_VAULT_OPERATOR_DELEGATION_DISCRIMINATOR = 7; -export function getInitializeVaultOperatorDelegationSnapshotDiscriminatorBytes() { +export function getSnapshotVaultOperatorDelegationDiscriminatorBytes() { return getU8Encoder().encode( - INITIALIZE_VAULT_OPERATOR_DELEGATION_SNAPSHOT_DISCRIMINATOR + SNAPSHOT_VAULT_OPERATOR_DELEGATION_DISCRIMINATOR ); } -export type InitializeVaultOperatorDelegationSnapshotInstruction< +export type SnapshotVaultOperatorDelegationInstruction< TProgram extends string = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, TAccountNcnConfig extends string | IAccountMeta = string, TAccountRestakingConfig extends string | IAccountMeta = string, @@ -104,16 +104,16 @@ export type InitializeVaultOperatorDelegationSnapshotInstruction< ] >; -export type InitializeVaultOperatorDelegationSnapshotInstructionData = { +export type SnapshotVaultOperatorDelegationInstructionData = { discriminator: number; firstSlotOfNcnEpoch: Option; }; -export type InitializeVaultOperatorDelegationSnapshotInstructionDataArgs = { +export type SnapshotVaultOperatorDelegationInstructionDataArgs = { firstSlotOfNcnEpoch: OptionOrNullable; }; -export function getInitializeVaultOperatorDelegationSnapshotInstructionDataEncoder(): Encoder { +export function getSnapshotVaultOperatorDelegationInstructionDataEncoder(): Encoder { return transformEncoder( getStructEncoder([ ['discriminator', getU8Encoder()], @@ -121,30 +121,29 @@ export function getInitializeVaultOperatorDelegationSnapshotInstructionDataEncod ]), (value) => ({ ...value, - discriminator: - INITIALIZE_VAULT_OPERATOR_DELEGATION_SNAPSHOT_DISCRIMINATOR, + discriminator: SNAPSHOT_VAULT_OPERATOR_DELEGATION_DISCRIMINATOR, }) ); } -export function getInitializeVaultOperatorDelegationSnapshotInstructionDataDecoder(): Decoder { +export function getSnapshotVaultOperatorDelegationInstructionDataDecoder(): Decoder { return getStructDecoder([ ['discriminator', getU8Decoder()], ['firstSlotOfNcnEpoch', getOptionDecoder(getU64Decoder())], ]); } -export function getInitializeVaultOperatorDelegationSnapshotInstructionDataCodec(): Codec< - InitializeVaultOperatorDelegationSnapshotInstructionDataArgs, - InitializeVaultOperatorDelegationSnapshotInstructionData +export function getSnapshotVaultOperatorDelegationInstructionDataCodec(): Codec< + SnapshotVaultOperatorDelegationInstructionDataArgs, + SnapshotVaultOperatorDelegationInstructionData > { return combineCodec( - getInitializeVaultOperatorDelegationSnapshotInstructionDataEncoder(), - getInitializeVaultOperatorDelegationSnapshotInstructionDataDecoder() + getSnapshotVaultOperatorDelegationInstructionDataEncoder(), + getSnapshotVaultOperatorDelegationInstructionDataDecoder() ); } -export type InitializeVaultOperatorDelegationSnapshotInput< +export type SnapshotVaultOperatorDelegationInput< TAccountNcnConfig extends string = string, TAccountRestakingConfig extends string = string, TAccountNcn extends string = string, @@ -172,10 +171,10 @@ export type InitializeVaultOperatorDelegationSnapshotInput< operatorSnapshot: Address; vaultProgram: Address; restakingProgram: Address; - firstSlotOfNcnEpoch: InitializeVaultOperatorDelegationSnapshotInstructionDataArgs['firstSlotOfNcnEpoch']; + firstSlotOfNcnEpoch: SnapshotVaultOperatorDelegationInstructionDataArgs['firstSlotOfNcnEpoch']; }; -export function getInitializeVaultOperatorDelegationSnapshotInstruction< +export function getSnapshotVaultOperatorDelegationInstruction< TAccountNcnConfig extends string, TAccountRestakingConfig extends string, TAccountNcn extends string, @@ -191,7 +190,7 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountRestakingProgram extends string, TProgramAddress extends Address = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, >( - input: InitializeVaultOperatorDelegationSnapshotInput< + input: SnapshotVaultOperatorDelegationInput< TAccountNcnConfig, TAccountRestakingConfig, TAccountNcn, @@ -207,7 +206,7 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< TAccountRestakingProgram >, config?: { programAddress?: TProgramAddress } -): InitializeVaultOperatorDelegationSnapshotInstruction< +): SnapshotVaultOperatorDelegationInstruction< TProgramAddress, TAccountNcnConfig, TAccountRestakingConfig, @@ -281,10 +280,10 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< getAccountMeta(accounts.restakingProgram), ], programAddress, - data: getInitializeVaultOperatorDelegationSnapshotInstructionDataEncoder().encode( - args as InitializeVaultOperatorDelegationSnapshotInstructionDataArgs + data: getSnapshotVaultOperatorDelegationInstructionDataEncoder().encode( + args as SnapshotVaultOperatorDelegationInstructionDataArgs ), - } as InitializeVaultOperatorDelegationSnapshotInstruction< + } as SnapshotVaultOperatorDelegationInstruction< TProgramAddress, TAccountNcnConfig, TAccountRestakingConfig, @@ -304,7 +303,7 @@ export function getInitializeVaultOperatorDelegationSnapshotInstruction< return instruction; } -export type ParsedInitializeVaultOperatorDelegationSnapshotInstruction< +export type ParsedSnapshotVaultOperatorDelegationInstruction< TProgram extends string = typeof JITO_TIP_ROUTER_PROGRAM_ADDRESS, TAccountMetas extends readonly IAccountMeta[] = readonly IAccountMeta[], > = { @@ -324,20 +323,17 @@ export type ParsedInitializeVaultOperatorDelegationSnapshotInstruction< vaultProgram: TAccountMetas[11]; restakingProgram: TAccountMetas[12]; }; - data: InitializeVaultOperatorDelegationSnapshotInstructionData; + data: SnapshotVaultOperatorDelegationInstructionData; }; -export function parseInitializeVaultOperatorDelegationSnapshotInstruction< +export function parseSnapshotVaultOperatorDelegationInstruction< TProgram extends string, TAccountMetas extends readonly IAccountMeta[], >( instruction: IInstruction & IInstructionWithAccounts & IInstructionWithData -): ParsedInitializeVaultOperatorDelegationSnapshotInstruction< - TProgram, - TAccountMetas -> { +): ParsedSnapshotVaultOperatorDelegationInstruction { if (instruction.accounts.length < 13) { // TODO: Coded error. throw new Error('Not enough accounts'); @@ -365,7 +361,7 @@ export function parseInitializeVaultOperatorDelegationSnapshotInstruction< vaultProgram: getNextAccount(), restakingProgram: getNextAccount(), }, - data: getInitializeVaultOperatorDelegationSnapshotInstructionDataDecoder().decode( + data: getSnapshotVaultOperatorDelegationInstructionDataDecoder().decode( instruction.data ), }; diff --git a/clients/js/jito_tip_router/programs/jitoTipRouter.ts b/clients/js/jito_tip_router/programs/jitoTipRouter.ts index fabcd39..29a98a9 100644 --- a/clients/js/jito_tip_router/programs/jitoTipRouter.ts +++ b/clients/js/jito_tip_router/programs/jitoTipRouter.ts @@ -18,11 +18,11 @@ import { type ParsedInitializeNCNConfigInstruction, type ParsedInitializeOperatorSnapshotInstruction, type ParsedInitializeTrackedMintsInstruction, - type ParsedInitializeVaultOperatorDelegationSnapshotInstruction, type ParsedInitializeWeightTableInstruction, type ParsedRegisterMintInstruction, type ParsedSetConfigFeesInstruction, type ParsedSetNewAdminInstruction, + type ParsedSnapshotVaultOperatorDelegationInstruction, } from '../instructions'; export const JITO_TIP_ROUTER_PROGRAM_ADDRESS = @@ -44,7 +44,7 @@ export enum JitoTipRouterInstruction { AdminUpdateWeightTable, InitializeEpochSnapshot, InitializeOperatorSnapshot, - InitializeVaultOperatorDelegationSnapshot, + SnapshotVaultOperatorDelegation, RegisterMint, InitializeTrackedMints, } @@ -75,7 +75,7 @@ export function identifyJitoTipRouterInstruction( return JitoTipRouterInstruction.InitializeOperatorSnapshot; } if (containsBytes(data, getU8Encoder().encode(7), 0)) { - return JitoTipRouterInstruction.InitializeVaultOperatorDelegationSnapshot; + return JitoTipRouterInstruction.SnapshotVaultOperatorDelegation; } if (containsBytes(data, getU8Encoder().encode(8), 0)) { return JitoTipRouterInstruction.RegisterMint; @@ -113,8 +113,8 @@ export type ParsedJitoTipRouterInstruction< instructionType: JitoTipRouterInstruction.InitializeOperatorSnapshot; } & ParsedInitializeOperatorSnapshotInstruction) | ({ - instructionType: JitoTipRouterInstruction.InitializeVaultOperatorDelegationSnapshot; - } & ParsedInitializeVaultOperatorDelegationSnapshotInstruction) + instructionType: JitoTipRouterInstruction.SnapshotVaultOperatorDelegation; + } & ParsedSnapshotVaultOperatorDelegationInstruction) | ({ instructionType: JitoTipRouterInstruction.RegisterMint; } & ParsedRegisterMintInstruction) diff --git a/clients/js/jito_tip_router/types/index.ts b/clients/js/jito_tip_router/types/index.ts index 788abb4..e93016f 100644 --- a/clients/js/jito_tip_router/types/index.ts +++ b/clients/js/jito_tip_router/types/index.ts @@ -10,5 +10,5 @@ export * from './configAdminRole'; export * from './fee'; export * from './fees'; export * from './mintEntry'; -export * from './vaultOperatorVotes'; +export * from './vaultOperatorStakeWeight'; export * from './weightEntry'; diff --git a/clients/js/jito_tip_router/types/vaultOperatorVotes.ts b/clients/js/jito_tip_router/types/vaultOperatorStakeWeight.ts similarity index 64% rename from clients/js/jito_tip_router/types/vaultOperatorVotes.ts rename to clients/js/jito_tip_router/types/vaultOperatorStakeWeight.ts index 3c2b8e1..bd2932c 100644 --- a/clients/js/jito_tip_router/types/vaultOperatorVotes.ts +++ b/clients/js/jito_tip_router/types/vaultOperatorStakeWeight.ts @@ -27,44 +27,44 @@ import { type ReadonlyUint8Array, } from '@solana/web3.js'; -export type VaultOperatorVotes = { +export type VaultOperatorStakeWeight = { vault: Address; - votes: bigint; + stakeWeight: bigint; vaultIndex: bigint; reserved: ReadonlyUint8Array; }; -export type VaultOperatorVotesArgs = { +export type VaultOperatorStakeWeightArgs = { vault: Address; - votes: number | bigint; + stakeWeight: number | bigint; vaultIndex: number | bigint; reserved: ReadonlyUint8Array; }; -export function getVaultOperatorVotesEncoder(): Encoder { +export function getVaultOperatorStakeWeightEncoder(): Encoder { return getStructEncoder([ ['vault', getAddressEncoder()], - ['votes', getU128Encoder()], + ['stakeWeight', getU128Encoder()], ['vaultIndex', getU64Encoder()], ['reserved', fixEncoderSize(getBytesEncoder(), 32)], ]); } -export function getVaultOperatorVotesDecoder(): Decoder { +export function getVaultOperatorStakeWeightDecoder(): Decoder { return getStructDecoder([ ['vault', getAddressDecoder()], - ['votes', getU128Decoder()], + ['stakeWeight', getU128Decoder()], ['vaultIndex', getU64Decoder()], ['reserved', fixDecoderSize(getBytesDecoder(), 32)], ]); } -export function getVaultOperatorVotesCodec(): Codec< - VaultOperatorVotesArgs, - VaultOperatorVotes +export function getVaultOperatorStakeWeightCodec(): Codec< + VaultOperatorStakeWeightArgs, + VaultOperatorStakeWeight > { return combineCodec( - getVaultOperatorVotesEncoder(), - getVaultOperatorVotesDecoder() + getVaultOperatorStakeWeightEncoder(), + getVaultOperatorStakeWeightDecoder() ); } diff --git a/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs b/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs index 20a1e24..991ef77 100644 --- a/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/accounts/epoch_snapshot.rs @@ -24,9 +24,10 @@ pub struct EpochSnapshot { pub slot_finalized: u64, pub ncn_fees: Fees, pub operator_count: u64, + pub vault_count: u64, pub operators_registered: u64, pub valid_operator_vault_delegations: u64, - pub total_votes: u128, + pub stake_weight: u128, #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] pub reserved: [u8; 128], } diff --git a/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs b/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs index e2e70fa..d392fc6 100644 --- a/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/accounts/operator_snapshot.rs @@ -7,7 +7,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; use solana_program::pubkey::Pubkey; -use crate::generated::types::VaultOperatorVotes; +use crate::generated::types::VaultOperatorStakeWeight; #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] @@ -33,11 +33,10 @@ pub struct OperatorSnapshot { pub vault_operator_delegation_count: u64, pub vault_operator_delegations_registered: u64, pub valid_operator_vault_delegations: u64, - pub total_votes: u128, + pub stake_weight: u128, #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] pub reserved: [u8; 256], - #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] - pub vault_operator_votes: [VaultOperatorVotes; 64], + pub vault_operator_stake_weight: [VaultOperatorStakeWeight; 32], } impl OperatorSnapshot { diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs b/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs index d19e7ae..8ee7e54 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/initialize_epoch_snapshot.rs @@ -14,6 +14,8 @@ pub struct InitializeEpochSnapshot { pub ncn: solana_program::pubkey::Pubkey, + pub tracked_mints: solana_program::pubkey::Pubkey, + pub weight_table: solana_program::pubkey::Pubkey, pub epoch_snapshot: solana_program::pubkey::Pubkey, @@ -38,7 +40,7 @@ impl InitializeEpochSnapshot { args: InitializeEpochSnapshotInstructionArgs, remaining_accounts: &[solana_program::instruction::AccountMeta], ) -> solana_program::instruction::Instruction { - let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(9 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new_readonly( self.ncn_config, false, @@ -50,6 +52,10 @@ impl InitializeEpochSnapshot { accounts.push(solana_program::instruction::AccountMeta::new_readonly( self.ncn, false, )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.tracked_mints, + false, + )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( self.weight_table, false, @@ -114,16 +120,18 @@ pub struct InitializeEpochSnapshotInstructionArgs { /// 0. `[]` ncn_config /// 1. `[]` restaking_config /// 2. `[]` ncn -/// 3. `[]` weight_table -/// 4. `[writable]` epoch_snapshot -/// 5. `[writable, signer]` payer -/// 6. `[]` restaking_program -/// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) +/// 3. `[]` tracked_mints +/// 4. `[]` weight_table +/// 5. `[writable]` epoch_snapshot +/// 6. `[writable, signer]` payer +/// 7. `[]` restaking_program +/// 8. `[optional]` system_program (default to `11111111111111111111111111111111`) #[derive(Clone, Debug, Default)] pub struct InitializeEpochSnapshotBuilder { ncn_config: Option, restaking_config: Option, ncn: Option, + tracked_mints: Option, weight_table: Option, epoch_snapshot: Option, payer: Option, @@ -156,6 +164,11 @@ impl InitializeEpochSnapshotBuilder { self } #[inline(always)] + pub fn tracked_mints(&mut self, tracked_mints: solana_program::pubkey::Pubkey) -> &mut Self { + self.tracked_mints = Some(tracked_mints); + self + } + #[inline(always)] pub fn weight_table(&mut self, weight_table: solana_program::pubkey::Pubkey) -> &mut Self { self.weight_table = Some(weight_table); self @@ -214,6 +227,7 @@ impl InitializeEpochSnapshotBuilder { ncn_config: self.ncn_config.expect("ncn_config is not set"), restaking_config: self.restaking_config.expect("restaking_config is not set"), ncn: self.ncn.expect("ncn is not set"), + tracked_mints: self.tracked_mints.expect("tracked_mints is not set"), weight_table: self.weight_table.expect("weight_table is not set"), epoch_snapshot: self.epoch_snapshot.expect("epoch_snapshot is not set"), payer: self.payer.expect("payer is not set"), @@ -240,6 +254,8 @@ pub struct InitializeEpochSnapshotCpiAccounts<'a, 'b> { pub ncn: &'b solana_program::account_info::AccountInfo<'a>, + pub tracked_mints: &'b solana_program::account_info::AccountInfo<'a>, + pub weight_table: &'b solana_program::account_info::AccountInfo<'a>, pub epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, @@ -262,6 +278,8 @@ pub struct InitializeEpochSnapshotCpi<'a, 'b> { pub ncn: &'b solana_program::account_info::AccountInfo<'a>, + pub tracked_mints: &'b solana_program::account_info::AccountInfo<'a>, + pub weight_table: &'b solana_program::account_info::AccountInfo<'a>, pub epoch_snapshot: &'b solana_program::account_info::AccountInfo<'a>, @@ -286,6 +304,7 @@ impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { ncn_config: accounts.ncn_config, restaking_config: accounts.restaking_config, ncn: accounts.ncn, + tracked_mints: accounts.tracked_mints, weight_table: accounts.weight_table, epoch_snapshot: accounts.epoch_snapshot, payer: accounts.payer, @@ -327,7 +346,7 @@ impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { bool, )], ) -> solana_program::entrypoint::ProgramResult { - let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + let mut accounts = Vec::with_capacity(9 + remaining_accounts.len()); accounts.push(solana_program::instruction::AccountMeta::new_readonly( *self.ncn_config.key, false, @@ -340,6 +359,10 @@ impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { *self.ncn.key, false, )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.tracked_mints.key, + false, + )); accounts.push(solana_program::instruction::AccountMeta::new_readonly( *self.weight_table.key, false, @@ -378,11 +401,12 @@ impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { accounts, data, }; - let mut account_infos = Vec::with_capacity(8 + 1 + remaining_accounts.len()); + let mut account_infos = Vec::with_capacity(9 + 1 + remaining_accounts.len()); account_infos.push(self.__program.clone()); account_infos.push(self.ncn_config.clone()); account_infos.push(self.restaking_config.clone()); account_infos.push(self.ncn.clone()); + account_infos.push(self.tracked_mints.clone()); account_infos.push(self.weight_table.clone()); account_infos.push(self.epoch_snapshot.clone()); account_infos.push(self.payer.clone()); @@ -407,11 +431,12 @@ impl<'a, 'b> InitializeEpochSnapshotCpi<'a, 'b> { /// 0. `[]` ncn_config /// 1. `[]` restaking_config /// 2. `[]` ncn -/// 3. `[]` weight_table -/// 4. `[writable]` epoch_snapshot -/// 5. `[writable, signer]` payer -/// 6. `[]` restaking_program -/// 7. `[]` system_program +/// 3. `[]` tracked_mints +/// 4. `[]` weight_table +/// 5. `[writable]` epoch_snapshot +/// 6. `[writable, signer]` payer +/// 7. `[]` restaking_program +/// 8. `[]` system_program #[derive(Clone, Debug)] pub struct InitializeEpochSnapshotCpiBuilder<'a, 'b> { instruction: Box>, @@ -424,6 +449,7 @@ impl<'a, 'b> InitializeEpochSnapshotCpiBuilder<'a, 'b> { ncn_config: None, restaking_config: None, ncn: None, + tracked_mints: None, weight_table: None, epoch_snapshot: None, payer: None, @@ -456,6 +482,14 @@ impl<'a, 'b> InitializeEpochSnapshotCpiBuilder<'a, 'b> { self } #[inline(always)] + pub fn tracked_mints( + &mut self, + tracked_mints: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.tracked_mints = Some(tracked_mints); + self + } + #[inline(always)] pub fn weight_table( &mut self, weight_table: &'b solana_program::account_info::AccountInfo<'a>, @@ -554,6 +588,11 @@ impl<'a, 'b> InitializeEpochSnapshotCpiBuilder<'a, 'b> { ncn: self.instruction.ncn.expect("ncn is not set"), + tracked_mints: self + .instruction + .tracked_mints + .expect("tracked_mints is not set"), + weight_table: self .instruction .weight_table @@ -590,6 +629,7 @@ struct InitializeEpochSnapshotCpiBuilderInstruction<'a, 'b> { ncn_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, restaking_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, ncn: Option<&'b solana_program::account_info::AccountInfo<'a>>, + tracked_mints: Option<&'b solana_program::account_info::AccountInfo<'a>>, weight_table: Option<&'b solana_program::account_info::AccountInfo<'a>>, epoch_snapshot: Option<&'b solana_program::account_info::AccountInfo<'a>>, payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, diff --git a/clients/rust/jito_tip_router/src/generated/instructions/mod.rs b/clients/rust/jito_tip_router/src/generated/instructions/mod.rs index 88dbead..06b2b50 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/mod.rs @@ -9,15 +9,15 @@ pub(crate) mod r#initialize_epoch_snapshot; pub(crate) mod r#initialize_n_c_n_config; pub(crate) mod r#initialize_operator_snapshot; pub(crate) mod r#initialize_tracked_mints; -pub(crate) mod r#initialize_vault_operator_delegation_snapshot; pub(crate) mod r#initialize_weight_table; pub(crate) mod r#register_mint; pub(crate) mod r#set_config_fees; pub(crate) mod r#set_new_admin; +pub(crate) mod r#snapshot_vault_operator_delegation; pub use self::{ r#admin_update_weight_table::*, r#initialize_epoch_snapshot::*, r#initialize_n_c_n_config::*, - r#initialize_operator_snapshot::*, r#initialize_tracked_mints::*, - r#initialize_vault_operator_delegation_snapshot::*, r#initialize_weight_table::*, + r#initialize_operator_snapshot::*, r#initialize_tracked_mints::*, r#initialize_weight_table::*, r#register_mint::*, r#set_config_fees::*, r#set_new_admin::*, + r#snapshot_vault_operator_delegation::*, }; diff --git a/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs b/clients/rust/jito_tip_router/src/generated/instructions/snapshot_vault_operator_delegation.rs similarity index 90% rename from clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs rename to clients/rust/jito_tip_router/src/generated/instructions/snapshot_vault_operator_delegation.rs index a1f8a1e..86b411b 100644 --- a/clients/rust/jito_tip_router/src/generated/instructions/initialize_vault_operator_delegation_snapshot.rs +++ b/clients/rust/jito_tip_router/src/generated/instructions/snapshot_vault_operator_delegation.rs @@ -7,7 +7,7 @@ use borsh::{BorshDeserialize, BorshSerialize}; /// Accounts. -pub struct InitializeVaultOperatorDelegationSnapshot { +pub struct SnapshotVaultOperatorDelegation { pub ncn_config: solana_program::pubkey::Pubkey, pub restaking_config: solana_program::pubkey::Pubkey, @@ -35,17 +35,17 @@ pub struct InitializeVaultOperatorDelegationSnapshot { pub restaking_program: solana_program::pubkey::Pubkey, } -impl InitializeVaultOperatorDelegationSnapshot { +impl SnapshotVaultOperatorDelegation { pub fn instruction( &self, - args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, + args: SnapshotVaultOperatorDelegationInstructionArgs, ) -> solana_program::instruction::Instruction { self.instruction_with_remaining_accounts(args, &[]) } #[allow(clippy::vec_init_then_push)] pub fn instruction_with_remaining_accounts( &self, - args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, + args: SnapshotVaultOperatorDelegationInstructionArgs, remaining_accounts: &[solana_program::instruction::AccountMeta], ) -> solana_program::instruction::Instruction { let mut accounts = Vec::with_capacity(13 + remaining_accounts.len()); @@ -100,7 +100,7 @@ impl InitializeVaultOperatorDelegationSnapshot { false, )); accounts.extend_from_slice(remaining_accounts); - let mut data = InitializeVaultOperatorDelegationSnapshotInstructionData::new() + let mut data = SnapshotVaultOperatorDelegationInstructionData::new() .try_to_vec() .unwrap(); let mut args = args.try_to_vec().unwrap(); @@ -115,17 +115,17 @@ impl InitializeVaultOperatorDelegationSnapshot { } #[derive(BorshDeserialize, BorshSerialize)] -pub struct InitializeVaultOperatorDelegationSnapshotInstructionData { +pub struct SnapshotVaultOperatorDelegationInstructionData { discriminator: u8, } -impl InitializeVaultOperatorDelegationSnapshotInstructionData { +impl SnapshotVaultOperatorDelegationInstructionData { pub fn new() -> Self { Self { discriminator: 7 } } } -impl Default for InitializeVaultOperatorDelegationSnapshotInstructionData { +impl Default for SnapshotVaultOperatorDelegationInstructionData { fn default() -> Self { Self::new() } @@ -133,11 +133,11 @@ impl Default for InitializeVaultOperatorDelegationSnapshotInstructionData { #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct InitializeVaultOperatorDelegationSnapshotInstructionArgs { +pub struct SnapshotVaultOperatorDelegationInstructionArgs { pub first_slot_of_ncn_epoch: Option, } -/// Instruction builder for `InitializeVaultOperatorDelegationSnapshot`. +/// Instruction builder for `SnapshotVaultOperatorDelegation`. /// /// ### Accounts: /// @@ -155,7 +155,7 @@ pub struct InitializeVaultOperatorDelegationSnapshotInstructionArgs { /// 11. `[]` vault_program /// 12. `[]` restaking_program #[derive(Clone, Debug, Default)] -pub struct InitializeVaultOperatorDelegationSnapshotBuilder { +pub struct SnapshotVaultOperatorDelegationBuilder { ncn_config: Option, restaking_config: Option, ncn: Option, @@ -173,7 +173,7 @@ pub struct InitializeVaultOperatorDelegationSnapshotBuilder { __remaining_accounts: Vec, } -impl InitializeVaultOperatorDelegationSnapshotBuilder { +impl SnapshotVaultOperatorDelegationBuilder { pub fn new() -> Self { Self::default() } @@ -286,7 +286,7 @@ impl InitializeVaultOperatorDelegationSnapshotBuilder { } #[allow(clippy::clone_on_copy)] pub fn instruction(&self) -> solana_program::instruction::Instruction { - let accounts = InitializeVaultOperatorDelegationSnapshot { + let accounts = SnapshotVaultOperatorDelegation { ncn_config: self.ncn_config.expect("ncn_config is not set"), restaking_config: self.restaking_config.expect("restaking_config is not set"), ncn: self.ncn.expect("ncn is not set"), @@ -307,7 +307,7 @@ impl InitializeVaultOperatorDelegationSnapshotBuilder { .restaking_program .expect("restaking_program is not set"), }; - let args = InitializeVaultOperatorDelegationSnapshotInstructionArgs { + let args = SnapshotVaultOperatorDelegationInstructionArgs { first_slot_of_ncn_epoch: self.first_slot_of_ncn_epoch.clone(), }; @@ -315,8 +315,8 @@ impl InitializeVaultOperatorDelegationSnapshotBuilder { } } -/// `initialize_vault_operator_delegation_snapshot` CPI accounts. -pub struct InitializeVaultOperatorDelegationSnapshotCpiAccounts<'a, 'b> { +/// `snapshot_vault_operator_delegation` CPI accounts. +pub struct SnapshotVaultOperatorDelegationCpiAccounts<'a, 'b> { pub ncn_config: &'b solana_program::account_info::AccountInfo<'a>, pub restaking_config: &'b solana_program::account_info::AccountInfo<'a>, @@ -344,8 +344,8 @@ pub struct InitializeVaultOperatorDelegationSnapshotCpiAccounts<'a, 'b> { pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, } -/// `initialize_vault_operator_delegation_snapshot` CPI instruction. -pub struct InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { +/// `snapshot_vault_operator_delegation` CPI instruction. +pub struct SnapshotVaultOperatorDelegationCpi<'a, 'b> { /// The program to invoke. pub __program: &'b solana_program::account_info::AccountInfo<'a>, @@ -375,14 +375,14 @@ pub struct InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { pub restaking_program: &'b solana_program::account_info::AccountInfo<'a>, /// The arguments for the instruction. - pub __args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, + pub __args: SnapshotVaultOperatorDelegationInstructionArgs, } -impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { +impl<'a, 'b> SnapshotVaultOperatorDelegationCpi<'a, 'b> { pub fn new( program: &'b solana_program::account_info::AccountInfo<'a>, - accounts: InitializeVaultOperatorDelegationSnapshotCpiAccounts<'a, 'b>, - args: InitializeVaultOperatorDelegationSnapshotInstructionArgs, + accounts: SnapshotVaultOperatorDelegationCpiAccounts<'a, 'b>, + args: SnapshotVaultOperatorDelegationInstructionArgs, ) -> Self { Self { __program: program, @@ -495,7 +495,7 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { is_writable: remaining_account.2, }) }); - let mut data = InitializeVaultOperatorDelegationSnapshotInstructionData::new() + let mut data = SnapshotVaultOperatorDelegationInstructionData::new() .try_to_vec() .unwrap(); let mut args = self.__args.try_to_vec().unwrap(); @@ -533,7 +533,7 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { } } -/// Instruction builder for `InitializeVaultOperatorDelegationSnapshot` via CPI. +/// Instruction builder for `SnapshotVaultOperatorDelegation` via CPI. /// /// ### Accounts: /// @@ -551,32 +551,30 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpi<'a, 'b> { /// 11. `[]` vault_program /// 12. `[]` restaking_program #[derive(Clone, Debug)] -pub struct InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { - instruction: Box>, +pub struct SnapshotVaultOperatorDelegationCpiBuilder<'a, 'b> { + instruction: Box>, } -impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { +impl<'a, 'b> SnapshotVaultOperatorDelegationCpiBuilder<'a, 'b> { pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { - let instruction = Box::new( - InitializeVaultOperatorDelegationSnapshotCpiBuilderInstruction { - __program: program, - ncn_config: None, - restaking_config: None, - ncn: None, - operator: None, - vault: None, - vault_ncn_ticket: None, - ncn_vault_ticket: None, - vault_operator_delegation: None, - weight_table: None, - epoch_snapshot: None, - operator_snapshot: None, - vault_program: None, - restaking_program: None, - first_slot_of_ncn_epoch: None, - __remaining_accounts: Vec::new(), - }, - ); + let instruction = Box::new(SnapshotVaultOperatorDelegationCpiBuilderInstruction { + __program: program, + ncn_config: None, + restaking_config: None, + ncn: None, + operator: None, + vault: None, + vault_ncn_ticket: None, + ncn_vault_ticket: None, + vault_operator_delegation: None, + weight_table: None, + epoch_snapshot: None, + operator_snapshot: None, + vault_program: None, + restaking_program: None, + first_slot_of_ncn_epoch: None, + __remaining_accounts: Vec::new(), + }); Self { instruction } } #[inline(always)] @@ -724,10 +722,10 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { &self, signers_seeds: &[&[&[u8]]], ) -> solana_program::entrypoint::ProgramResult { - let args = InitializeVaultOperatorDelegationSnapshotInstructionArgs { + let args = SnapshotVaultOperatorDelegationInstructionArgs { first_slot_of_ncn_epoch: self.instruction.first_slot_of_ncn_epoch.clone(), }; - let instruction = InitializeVaultOperatorDelegationSnapshotCpi { + let instruction = SnapshotVaultOperatorDelegationCpi { __program: self.instruction.__program, ncn_config: self.instruction.ncn_config.expect("ncn_config is not set"), @@ -792,7 +790,7 @@ impl<'a, 'b> InitializeVaultOperatorDelegationSnapshotCpiBuilder<'a, 'b> { } #[derive(Clone, Debug)] -struct InitializeVaultOperatorDelegationSnapshotCpiBuilderInstruction<'a, 'b> { +struct SnapshotVaultOperatorDelegationCpiBuilderInstruction<'a, 'b> { __program: &'b solana_program::account_info::AccountInfo<'a>, ncn_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, restaking_config: Option<&'b solana_program::account_info::AccountInfo<'a>>, diff --git a/clients/rust/jito_tip_router/src/generated/types/mod.rs b/clients/rust/jito_tip_router/src/generated/types/mod.rs index 9f74ec9..f19946a 100644 --- a/clients/rust/jito_tip_router/src/generated/types/mod.rs +++ b/clients/rust/jito_tip_router/src/generated/types/mod.rs @@ -8,10 +8,10 @@ pub(crate) mod r#config_admin_role; pub(crate) mod r#fee; pub(crate) mod r#fees; pub(crate) mod r#mint_entry; -pub(crate) mod r#vault_operator_votes; +pub(crate) mod r#vault_operator_stake_weight; pub(crate) mod r#weight_entry; pub use self::{ - r#config_admin_role::*, r#fee::*, r#fees::*, r#mint_entry::*, r#vault_operator_votes::*, + r#config_admin_role::*, r#fee::*, r#fees::*, r#mint_entry::*, r#vault_operator_stake_weight::*, r#weight_entry::*, }; diff --git a/clients/rust/jito_tip_router/src/generated/types/vault_operator_votes.rs b/clients/rust/jito_tip_router/src/generated/types/vault_operator_stake_weight.rs similarity index 90% rename from clients/rust/jito_tip_router/src/generated/types/vault_operator_votes.rs rename to clients/rust/jito_tip_router/src/generated/types/vault_operator_stake_weight.rs index 43941b5..e45eb5b 100644 --- a/clients/rust/jito_tip_router/src/generated/types/vault_operator_votes.rs +++ b/clients/rust/jito_tip_router/src/generated/types/vault_operator_stake_weight.rs @@ -9,13 +9,13 @@ use solana_program::pubkey::Pubkey; #[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct VaultOperatorVotes { +pub struct VaultOperatorStakeWeight { #[cfg_attr( feature = "serde", serde(with = "serde_with::As::") )] pub vault: Pubkey, - pub votes: u128, + pub stake_weight: u128, pub vault_index: u64, pub reserved: [u8; 32], } diff --git a/core/src/epoch_snapshot.rs b/core/src/epoch_snapshot.rs index 6c31ad5..db300f6 100644 --- a/core/src/epoch_snapshot.rs +++ b/core/src/epoch_snapshot.rs @@ -33,12 +33,13 @@ pub struct EpochSnapshot { ncn_fees: Fees, operator_count: PodU64, + vault_count: PodU64, operators_registered: PodU64, valid_operator_vault_delegations: PodU64, /// Counted as each delegate gets added ///TODO What happens if `finalized() && total_votes() == 0`? - total_votes: PodU128, + stake_weight: PodU128, /// Reserved space reserved: [u8; 128], @@ -55,7 +56,8 @@ impl EpochSnapshot { bump: u8, current_slot: u64, ncn_fees: Fees, - num_operators: u64, + operator_count: u64, + vault_count: u64, ) -> Self { Self { ncn, @@ -64,10 +66,11 @@ impl EpochSnapshot { slot_finalized: PodU64::from(0), bump, ncn_fees, - operator_count: PodU64::from(num_operators), + operator_count: PodU64::from(operator_count), + vault_count: PodU64::from(vault_count), operators_registered: PodU64::from(0), valid_operator_vault_delegations: PodU64::from(0), - total_votes: PodU128::from(0), + stake_weight: PodU128::from(0), reserved: [0; 128], } } @@ -75,7 +78,7 @@ impl EpochSnapshot { pub fn seeds(ncn: &Pubkey, ncn_epoch: u64) -> Vec> { Vec::from_iter( [ - b"EPOCH_SNAPSHOT".to_vec(), + b"epoch_snapshot".to_vec(), ncn.to_bytes().to_vec(), ncn_epoch.to_le_bytes().to_vec(), ] @@ -132,6 +135,10 @@ impl EpochSnapshot { self.operator_count.into() } + pub fn vault_count(&self) -> u64 { + self.vault_count.into() + } + pub fn operators_registered(&self) -> u64 { self.operators_registered.into() } @@ -140,8 +147,8 @@ impl EpochSnapshot { self.valid_operator_vault_delegations.into() } - pub fn total_votes(&self) -> u128 { - self.total_votes.into() + pub fn stake_weight(&self) -> u128 { + self.stake_weight.into() } pub fn finalized(&self) -> bool { @@ -152,7 +159,7 @@ impl EpochSnapshot { &mut self, current_slot: u64, vault_operator_delegations: u64, - votes: u128, + stake_weight: u128, ) -> Result<(), TipRouterError> { if self.finalized() { return Err(TipRouterError::OperatorFinalized); @@ -170,9 +177,9 @@ impl EpochSnapshot { .ok_or(TipRouterError::ArithmeticOverflow)?, ); - self.total_votes = PodU128::from( - self.total_votes() - .checked_add(votes) + self.stake_weight = PodU128::from( + self.stake_weight() + .checked_add(stake_weight) .ok_or(TipRouterError::ArithmeticOverflow)?, ); @@ -205,39 +212,39 @@ pub struct OperatorSnapshot { vault_operator_delegations_registered: PodU64, valid_operator_vault_delegations: PodU64, - total_votes: PodU128, + stake_weight: PodU128, reserved: [u8; 256], - // needs to be last item in struct such that it can grow later - vault_operator_votes: [VaultOperatorVotes; 64], + //TODO change to 64 + vault_operator_stake_weight: [VaultOperatorStakeWeight; 32], } #[derive(Debug, Clone, Copy, Zeroable, ShankType, Pod, ShankType)] #[repr(C)] -pub struct VaultOperatorVotes { +pub struct VaultOperatorStakeWeight { vault: Pubkey, - votes: PodU128, + stake_weight: PodU128, vault_index: PodU64, reserved: [u8; 32], } -impl Default for VaultOperatorVotes { +impl Default for VaultOperatorStakeWeight { fn default() -> Self { Self { vault: Pubkey::default(), vault_index: PodU64::from(u64::MAX), - votes: PodU128::from(0), + stake_weight: PodU128::from(0), reserved: [0; 32], } } } -impl VaultOperatorVotes { - pub fn new(vault: Pubkey, votes: u128, vault_index: u64) -> Self { +impl VaultOperatorStakeWeight { + pub fn new(vault: Pubkey, stake_weight: u128, vault_index: u64) -> Self { Self { vault, vault_index: PodU64::from(vault_index), - votes: PodU128::from(votes), + stake_weight: PodU128::from(stake_weight), reserved: [0; 32], } } @@ -250,8 +257,8 @@ impl VaultOperatorVotes { self.vault_index.into() } - pub fn votes(&self) -> u128 { - self.votes.into() + pub fn stake_weight(&self) -> u128 { + self.stake_weight.into() } } @@ -260,7 +267,7 @@ impl Discriminator for OperatorSnapshot { } impl OperatorSnapshot { - pub const MAX_VAULT_OPERATOR_VOTES: usize = 64; + pub const MAX_VAULT_OPERATOR_STAKE_WEIGHT: usize = 64; #[allow(clippy::too_many_arguments)] pub fn new( @@ -274,7 +281,7 @@ impl OperatorSnapshot { operator_fee_bps: u16, vault_operator_delegation_count: u64, ) -> Result { - if vault_operator_delegation_count > Self::MAX_VAULT_OPERATOR_VOTES as u64 { + if vault_operator_delegation_count > Self::MAX_VAULT_OPERATOR_STAKE_WEIGHT as u64 { return Err(TipRouterError::TooManyVaultOperatorDelegations); } @@ -291,9 +298,9 @@ impl OperatorSnapshot { vault_operator_delegation_count: PodU64::from(vault_operator_delegation_count), vault_operator_delegations_registered: PodU64::from(0), valid_operator_vault_delegations: PodU64::from(0), - total_votes: PodU128::from(0), + stake_weight: PodU128::from(0), reserved: [0; 256], - vault_operator_votes: [VaultOperatorVotes::default(); 64], + vault_operator_stake_weight: [VaultOperatorStakeWeight::default(); 32], }) } @@ -348,7 +355,7 @@ impl OperatorSnapshot { pub fn seeds(operator: &Pubkey, ncn: &Pubkey, ncn_epoch: u64) -> Vec> { Vec::from_iter( [ - b"OPERATOR_SNAPSHOT".to_vec(), + b"operator_snapshot".to_vec(), operator.to_bytes().to_vec(), ncn.to_bytes().to_vec(), ncn_epoch.to_le_bytes().to_vec(), @@ -416,8 +423,8 @@ impl OperatorSnapshot { self.valid_operator_vault_delegations.into() } - pub fn total_votes(&self) -> u128 { - self.total_votes.into() + pub fn stake_weight(&self) -> u128 { + self.stake_weight.into() } pub fn finalized(&self) -> bool { @@ -425,18 +432,20 @@ impl OperatorSnapshot { } pub fn contains_vault_index(&self, vault_index: u64) -> bool { - self.vault_operator_votes + self.vault_operator_stake_weight .iter() .any(|v| v.vault_index() == vault_index) } - pub fn insert_vault_operator_votes( + pub fn insert_vault_operator_stake_weight( &mut self, vault: Pubkey, vault_index: u64, - votes: u128, + stake_weight: u128, ) -> Result<(), TipRouterError> { - if self.vault_operator_delegations_registered() > Self::MAX_VAULT_OPERATOR_VOTES as u64 { + if self.vault_operator_delegations_registered() + > Self::MAX_VAULT_OPERATOR_STAKE_WEIGHT as u64 + { return Err(TipRouterError::TooManyVaultOperatorDelegations); } @@ -444,8 +453,8 @@ impl OperatorSnapshot { return Err(TipRouterError::DuplicateVaultOperatorDelegation); } - self.vault_operator_votes[self.vault_operator_delegations_registered() as usize] = - VaultOperatorVotes::new(vault, votes, vault_index); + self.vault_operator_stake_weight[self.vault_operator_delegations_registered() as usize] = + VaultOperatorStakeWeight::new(vault, stake_weight, vault_index); Ok(()) } @@ -455,13 +464,13 @@ impl OperatorSnapshot { current_slot: u64, vault: Pubkey, vault_index: u64, - votes: u128, + stake_weight: u128, ) -> Result<(), TipRouterError> { if self.finalized() { return Err(TipRouterError::VaultOperatorDelegationFinalized); } - self.insert_vault_operator_votes(vault, vault_index, votes)?; + self.insert_vault_operator_stake_weight(vault, vault_index, stake_weight)?; self.vault_operator_delegations_registered = PodU64::from( self.vault_operator_delegations_registered() @@ -469,7 +478,7 @@ impl OperatorSnapshot { .ok_or(TipRouterError::ArithmeticOverflow)?, ); - if votes > 0 { + if stake_weight > 0 { self.valid_operator_vault_delegations = PodU64::from( self.valid_operator_vault_delegations() .checked_add(1) @@ -477,9 +486,9 @@ impl OperatorSnapshot { ); } - self.total_votes = PodU128::from( - self.total_votes() - .checked_add(votes) + self.stake_weight = PodU128::from( + self.stake_weight() + .checked_add(stake_weight) .ok_or(TipRouterError::ArithmeticOverflow)?, ); @@ -490,7 +499,7 @@ impl OperatorSnapshot { Ok(()) } - pub fn calculate_total_votes( + pub fn calculate_total_stake_weight( vault_operator_delegation: &VaultOperatorDelegation, weight_table: &WeightTable, st_mint: &Pubkey, @@ -504,14 +513,14 @@ impl OperatorSnapshot { let precise_weight = weight_table.get_precise_weight(st_mint)?; - let precise_total_votes = precise_total_security + let precise_total_stake_weight = precise_total_security .checked_mul(&precise_weight) .ok_or(TipRouterError::ArithmeticOverflow)?; - let total_votes = precise_total_votes + let total_stake_weight = precise_total_stake_weight .to_imprecise() .ok_or(TipRouterError::CastToImpreciseNumberError)?; - Ok(total_votes) + Ok(total_stake_weight) } } diff --git a/core/src/instruction.rs b/core/src/instruction.rs index bc439b7..bc42ba6 100644 --- a/core/src/instruction.rs +++ b/core/src/instruction.rs @@ -78,11 +78,12 @@ pub enum TipRouterInstruction { #[account(0, name = "ncn_config")] #[account(1, name = "restaking_config")] #[account(2, name = "ncn")] - #[account(3, name = "weight_table")] - #[account(4, writable, name = "epoch_snapshot")] - #[account(5, writable, signer, name = "payer")] - #[account(6, name = "restaking_program")] - #[account(7, name = "system_program")] + #[account(3, name = "tracked_mints")] + #[account(4, name = "weight_table")] + #[account(5, writable, name = "epoch_snapshot")] + #[account(6, writable, signer, name = "payer")] + #[account(7, name = "restaking_program")] + #[account(8, name = "system_program")] InitializeEpochSnapshot{ first_slot_of_ncn_epoch: Option, }, @@ -116,7 +117,7 @@ pub enum TipRouterInstruction { #[account(10, writable, name = "operator_snapshot")] #[account(11, name = "vault_program")] #[account(12, name = "restaking_program")] - InitializeVaultOperatorDelegationSnapshot{ + SnapshotVaultOperatorDelegation{ first_slot_of_ncn_epoch: Option, }, /// Registers a mint with the NCN config diff --git a/idl/jito_tip_router.json b/idl/jito_tip_router.json index e551af3..7f59e84 100644 --- a/idl/jito_tip_router.json +++ b/idl/jito_tip_router.json @@ -281,6 +281,11 @@ "isMut": false, "isSigner": false }, + { + "name": "trackedMints", + "isMut": false, + "isSigner": false + }, { "name": "weightTable", "isMut": false, @@ -388,7 +393,7 @@ } }, { - "name": "InitializeVaultOperatorDelegationSnapshot", + "name": "SnapshotVaultOperatorDelegation", "accounts": [ { "name": "ncnConfig", @@ -604,6 +609,12 @@ "defined": "PodU64" } }, + { + "name": "vaultCount", + "type": { + "defined": "PodU64" + } + }, { "name": "operatorsRegistered", "type": { @@ -617,7 +628,7 @@ } }, { - "name": "totalVotes", + "name": "stakeWeight", "type": { "defined": "PodU128" } @@ -706,7 +717,7 @@ } }, { - "name": "totalVotes", + "name": "stakeWeight", "type": { "defined": "PodU128" } @@ -721,13 +732,13 @@ } }, { - "name": "vaultOperatorVotes", + "name": "vaultOperatorStakeWeight", "type": { "array": [ { - "defined": "VaultOperatorVotes" + "defined": "VaultOperatorStakeWeight" }, - 64 + 32 ] } } @@ -860,7 +871,7 @@ ], "types": [ { - "name": "VaultOperatorVotes", + "name": "VaultOperatorStakeWeight", "type": { "kind": "struct", "fields": [ @@ -869,7 +880,7 @@ "type": "publicKey" }, { - "name": "votes", + "name": "stakeWeight", "type": { "defined": "PodU128" } diff --git a/integration_tests/tests/fixtures/test_builder.rs b/integration_tests/tests/fixtures/test_builder.rs index 35cde4e..74b03b6 100644 --- a/integration_tests/tests/fixtures/test_builder.rs +++ b/integration_tests/tests/fixtures/test_builder.rs @@ -447,7 +447,7 @@ impl TestBuilder { let vault = vault_root.vault_pubkey; tip_router_client - .do_initalize_vault_operator_delegation_snapshot(vault, operator, ncn, slot) + .do_snapshot_vault_operator_delegation(vault, operator, ncn, slot) .await?; } } diff --git a/integration_tests/tests/fixtures/tip_router_client.rs b/integration_tests/tests/fixtures/tip_router_client.rs index 86f8c5e..dc6cae5 100644 --- a/integration_tests/tests/fixtures/tip_router_client.rs +++ b/integration_tests/tests/fixtures/tip_router_client.rs @@ -6,8 +6,8 @@ use jito_tip_router_client::{ instructions::{ AdminUpdateWeightTableBuilder, InitializeEpochSnapshotBuilder, InitializeNCNConfigBuilder, InitializeOperatorSnapshotBuilder, InitializeTrackedMintsBuilder, - InitializeVaultOperatorDelegationSnapshotBuilder, InitializeWeightTableBuilder, - RegisterMintBuilder, SetConfigFeesBuilder, SetNewAdminBuilder, + InitializeWeightTableBuilder, RegisterMintBuilder, SetConfigFeesBuilder, + SetNewAdminBuilder, SnapshotVaultOperatorDelegationBuilder, }, types::ConfigAdminRole, }; @@ -15,7 +15,7 @@ use jito_tip_router_core::{ epoch_snapshot::{EpochSnapshot, OperatorSnapshot}, error::TipRouterError, ncn_config::NcnConfig, - tracked_mints::TrackedMints, + tracked_mints::{self, TrackedMints}, weight_table::WeightTable, }; use jito_vault_core::{ @@ -499,6 +499,8 @@ impl TipRouterClient { let ncn_epoch = slot / restaking_config_account.epoch_length(); let config_pda = NcnConfig::find_program_address(&jito_tip_router_program::id(), &ncn).0; + let tracked_mints = + TrackedMints::find_program_address(&jito_tip_router_program::id(), &ncn).0; let weight_table = WeightTable::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; @@ -509,6 +511,7 @@ impl TipRouterClient { .ncn_config(config_pda) .restaking_config(restaking_config) .ncn(ncn) + .tracked_mints(tracked_mints) .weight_table(weight_table) .epoch_snapshot(epoch_snapshot) .payer(self.payer.pubkey()) @@ -588,18 +591,18 @@ impl TipRouterClient { .await } - pub async fn do_initalize_vault_operator_delegation_snapshot( + pub async fn do_snapshot_vault_operator_delegation( &mut self, vault: Pubkey, operator: Pubkey, ncn: Pubkey, slot: u64, ) -> TestResult<()> { - self.initalize_vault_operator_delegation_snapshot(vault, operator, ncn, slot) + self.snapshot_vault_operator_delegation(vault, operator, ncn, slot) .await } - pub async fn initalize_vault_operator_delegation_snapshot( + pub async fn snapshot_vault_operator_delegation( &mut self, vault: Pubkey, operator: Pubkey, @@ -640,7 +643,7 @@ impl TipRouterClient { let weight_table = WeightTable::find_program_address(&jito_tip_router_program::id(), &ncn, ncn_epoch).0; - let ix = InitializeVaultOperatorDelegationSnapshotBuilder::new() + let ix = SnapshotVaultOperatorDelegationBuilder::new() .ncn_config(config_pda) .restaking_config(restaking_config) .ncn(ncn) diff --git a/integration_tests/tests/tip_router/mod.rs b/integration_tests/tests/tip_router/mod.rs index 99b6f14..43d86a4 100644 --- a/integration_tests/tests/tip_router/mod.rs +++ b/integration_tests/tests/tip_router/mod.rs @@ -3,9 +3,9 @@ mod initialize_epoch_snapshot; mod initialize_ncn_config; mod initialize_operator_snapshot; mod initialize_tracked_mints; -mod initialize_vault_operator_delegation_snapshot; mod initialize_weight_table; mod meta_tests; mod register_mint; mod set_config_fees; mod set_new_admin; +mod snapshot_vault_operator_delegation; diff --git a/integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs b/integration_tests/tests/tip_router/snapshot_vault_operator_delegation.rs similarity index 93% rename from integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs rename to integration_tests/tests/tip_router/snapshot_vault_operator_delegation.rs index d7c1475..7987350 100644 --- a/integration_tests/tests/tip_router/initialize_vault_operator_delegation_snapshot.rs +++ b/integration_tests/tests/tip_router/snapshot_vault_operator_delegation.rs @@ -43,7 +43,7 @@ mod tests { .await?; tip_router_client - .do_initalize_vault_operator_delegation_snapshot(vault_address, operator, ncn, slot) + .do_snapshot_vault_operator_delegation(vault_address, operator, ncn, slot) .await?; Ok(()) diff --git a/program/src/initialize_epoch_snapshot.rs b/program/src/initialize_epoch_snapshot.rs index 8ae74a1..1814bb4 100644 --- a/program/src/initialize_epoch_snapshot.rs +++ b/program/src/initialize_epoch_snapshot.rs @@ -6,7 +6,7 @@ use jito_jsm_core::{ use jito_restaking_core::{config::Config, ncn::Ncn}; use jito_tip_router_core::{ epoch_snapshot::EpochSnapshot, error::TipRouterError, fees, loaders::load_ncn_epoch, - ncn_config::NcnConfig, weight_table::WeightTable, + ncn_config::NcnConfig, tracked_mints::TrackedMints, weight_table::WeightTable, }; use solana_program::{ account_info::AccountInfo, clock::Clock, entrypoint::ProgramResult, msg, @@ -19,7 +19,7 @@ pub fn process_initialize_epoch_snapshot( accounts: &[AccountInfo], first_slot_of_ncn_epoch: Option, ) -> ProgramResult { - let [ncn_config, restaking_config, ncn, weight_table, epoch_snapshot, payer, restaking_program, system_program] = + let [ncn_config, restaking_config, ncn, tracked_mints, weight_table, epoch_snapshot, payer, restaking_program, system_program] = accounts else { return Err(ProgramError::NotEnoughAccountKeys); @@ -33,6 +33,7 @@ pub fn process_initialize_epoch_snapshot( NcnConfig::load(program_id, ncn.key, ncn_config, false)?; Config::load(restaking_program.key, restaking_config, false)?; Ncn::load(restaking_program.key, ncn, false)?; + TrackedMints::load(program_id, ncn.key, tracked_mints, false)?; load_system_account(epoch_snapshot, true)?; load_system_program(system_program)?; @@ -94,6 +95,12 @@ pub fn process_initialize_epoch_snapshot( ncn_account.operator_count() }; + let vault_count: u64 = { + let tracked_mints_data = tracked_mints.data.borrow(); + let tracked_mints_account = TrackedMints::try_from_slice_unchecked(&tracked_mints_data)?; + tracked_mints_account.mint_count() + }; + if operator_count == 0 { msg!("No operators to snapshot"); return Err(TipRouterError::NoOperators.into()); @@ -112,6 +119,7 @@ pub fn process_initialize_epoch_snapshot( current_slot, ncn_fees, operator_count, + vault_count, ); Ok(()) diff --git a/program/src/initialize_operator_snapshot.rs b/program/src/initialize_operator_snapshot.rs index e1b6df7..ac78aff 100644 --- a/program/src/initialize_operator_snapshot.rs +++ b/program/src/initialize_operator_snapshot.rs @@ -99,12 +99,17 @@ pub fn process_initialize_operator_snapshot( ncn_operator_okay && operator_ncn_okay }; - let (operator_fee_bps, vault_count, operator_index): (u16, u64, u64) = { + let vault_count = { + let epoch_snapshot_data = epoch_snapshot.data.borrow(); + let epoch_snapshot_account = EpochSnapshot::try_from_slice_unchecked(&epoch_snapshot_data)?; + epoch_snapshot_account.vault_count() + }; + + let (operator_fee_bps, operator_index): (u16, u64) = { let operator_data = operator.data.borrow(); let operator_account = Operator::try_from_slice_unchecked(&operator_data)?; ( operator_account.operator_fee_bps.into(), - operator_account.vault_count(), operator_account.index(), ) }; diff --git a/program/src/lib.rs b/program/src/lib.rs index 7bc5628..df0b144 100644 --- a/program/src/lib.rs +++ b/program/src/lib.rs @@ -3,11 +3,11 @@ mod initialize_epoch_snapshot; mod initialize_ncn_config; mod initialize_operator_snapshot; mod initialize_tracked_mints; -mod initialize_vault_operator_delegation_snapshot; mod initialize_weight_table; mod register_mint; mod set_config_fees; mod set_new_admin; +mod snapshot_vault_operator_delegation; use borsh::BorshDeserialize; use const_str_to_pubkey::str_to_pubkey; @@ -26,9 +26,9 @@ use crate::{ initialize_ncn_config::process_initialize_ncn_config, initialize_operator_snapshot::process_initialize_operator_snapshot, initialize_tracked_mints::process_initialize_tracked_mints, - initialize_vault_operator_delegation_snapshot::process_initialize_vault_operator_delegation_snapshot, initialize_weight_table::process_initialize_weight_table, register_mint::process_register_mint, set_config_fees::process_set_config_fees, + snapshot_vault_operator_delegation::process_snapshot_vault_operator_delegation, }; declare_id!(str_to_pubkey(env!("TIP_ROUTER_PROGRAM_ID"))); @@ -95,11 +95,11 @@ pub fn process_instruction( msg!("Instruction: InitializeOperatorSnapshot"); process_initialize_operator_snapshot(program_id, accounts, first_slot_of_ncn_epoch) } - TipRouterInstruction::InitializeVaultOperatorDelegationSnapshot { + TipRouterInstruction::SnapshotVaultOperatorDelegation { first_slot_of_ncn_epoch, } => { msg!("Instruction: InitializeVaultOperatorDelegationSnapshot"); - process_initialize_vault_operator_delegation_snapshot( + process_snapshot_vault_operator_delegation( program_id, accounts, first_slot_of_ncn_epoch, diff --git a/program/src/initialize_vault_operator_delegation_snapshot.rs b/program/src/snapshot_vault_operator_delegation.rs similarity index 92% rename from program/src/initialize_vault_operator_delegation_snapshot.rs rename to program/src/snapshot_vault_operator_delegation.rs index 2d1bcb3..65c0847 100644 --- a/program/src/initialize_vault_operator_delegation_snapshot.rs +++ b/program/src/snapshot_vault_operator_delegation.rs @@ -17,7 +17,7 @@ use solana_program::{ program_error::ProgramError, pubkey::Pubkey, sysvar::Sysvar, }; -pub fn process_initialize_vault_operator_delegation_snapshot( +pub fn process_snapshot_vault_operator_delegation( program_id: &Pubkey, accounts: &[AccountInfo], first_slot_of_ncn_epoch: Option, @@ -54,9 +54,6 @@ pub fn process_initialize_vault_operator_delegation_snapshot( VaultNcnTicket::load(vault_program.key, vault_ncn_ticket, vault, ncn, false)?; NcnVaultTicket::load(restaking_program.key, ncn_vault_ticket, ncn, vault, false)?; - //TODO check that st mint is supported? - //TODO may not exist - //TODO what happens if a new Vault is added inbetween weight table creation and this? - There could be a count mismatch if !vault_operator_delegation.data_is_empty() { VaultOperatorDelegation::load( vault_program.key, @@ -107,7 +104,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( let delegation_dne = vault_operator_delegation.data_is_empty(); - vault_ncn_okay && ncn_vault_okay && delegation_dne + vault_ncn_okay && ncn_vault_okay && !delegation_dne }; let total_votes: u128 = if is_active { @@ -118,7 +115,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( let weight_table_data = weight_table.data.borrow(); let weight_table_account = WeightTable::try_from_slice_unchecked(&weight_table_data)?; - OperatorSnapshot::calculate_total_votes( + OperatorSnapshot::calculate_total_stake_weight( vault_operator_delegation_account, weight_table_account, &st_mint, @@ -148,7 +145,7 @@ pub fn process_initialize_vault_operator_delegation_snapshot( epoch_snapshot_account.increment_operator_registration( current_slot, operator_snapshot_account.valid_operator_vault_delegations(), - operator_snapshot_account.total_votes(), + operator_snapshot_account.stake_weight(), )?; } From 7fb0e4d87764b28e5f9d1ad105ad5f6d96f0dcfd Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Tue, 19 Nov 2024 10:19:41 -0600 Subject: [PATCH 23/28] TODOs added --- program/src/initialize_operator_snapshot.rs | 1 + program/src/snapshot_vault_operator_delegation.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/program/src/initialize_operator_snapshot.rs b/program/src/initialize_operator_snapshot.rs index ac78aff..0c2d84e 100644 --- a/program/src/initialize_operator_snapshot.rs +++ b/program/src/initialize_operator_snapshot.rs @@ -83,6 +83,7 @@ pub fn process_initialize_operator_snapshot( &operator_snapshot_seeds, )?; + //TODO move to helper function let is_active: bool = { let ncn_operator_state_data = ncn_operator_state.data.borrow(); let ncn_operator_state_account = diff --git a/program/src/snapshot_vault_operator_delegation.rs b/program/src/snapshot_vault_operator_delegation.rs index 65c0847..fdb2dba 100644 --- a/program/src/snapshot_vault_operator_delegation.rs +++ b/program/src/snapshot_vault_operator_delegation.rs @@ -85,6 +85,7 @@ pub fn process_snapshot_vault_operator_delegation( (vault_account.vault_index(), vault_account.supported_mint) }; + //TODO move to helper function let is_active: bool = { let vault_ncn_ticket_data = vault_ncn_ticket.data.borrow(); let vault_ncn_ticket_account = From 9d9b415a00436cbd140519be3de922610461e203 Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Tue, 19 Nov 2024 11:15:55 -0600 Subject: [PATCH 24/28] fixed dead code --- .config/nextest.toml | 5 ++++ .../tests/fixtures/restaking_client.rs | 17 +++++++++++ .../tests/fixtures/test_builder.rs | 24 ++++----------- .../tests/fixtures/tip_router_client.rs | 4 ++- .../tests/fixtures/vault_client.rs | 30 +++++++++++++++++-- 5 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 .config/nextest.toml diff --git a/.config/nextest.toml b/.config/nextest.toml new file mode 100644 index 0000000..7544d59 --- /dev/null +++ b/.config/nextest.toml @@ -0,0 +1,5 @@ +[profile.default] +retries = { backoff = "exponential", count = 5, delay = "1s", jitter = true, max-delay = "10s" } +test-threads = 1 +threads-required = 1 +fail-fast = false \ No newline at end of file diff --git a/integration_tests/tests/fixtures/restaking_client.rs b/integration_tests/tests/fixtures/restaking_client.rs index 186daa9..c8e817e 100644 --- a/integration_tests/tests/fixtures/restaking_client.rs +++ b/integration_tests/tests/fixtures/restaking_client.rs @@ -73,6 +73,7 @@ impl RestakingProgramClient { } } + #[allow(dead_code)] pub async fn get_ncn(&mut self, ncn: &Pubkey) -> TestResult { let account = self .banks_client @@ -95,6 +96,7 @@ impl RestakingProgramClient { Ok(config.get_epoch_from_slot(slot).unwrap()) } + #[allow(dead_code)] pub async fn get_ncn_vault_ticket( &mut self, ncn: &Pubkey, @@ -108,6 +110,7 @@ impl RestakingProgramClient { )?) } + #[allow(dead_code)] pub async fn get_ncn_operator_state( &mut self, ncn: &Pubkey, @@ -121,6 +124,7 @@ impl RestakingProgramClient { )?) } + #[allow(dead_code)] pub async fn get_operator(&mut self, account: &Pubkey) -> TestResult { let account = self.banks_client.get_account(*account).await?.unwrap(); Ok(*Operator::try_from_slice_unchecked( @@ -128,6 +132,7 @@ impl RestakingProgramClient { )?) } + #[allow(dead_code)] pub async fn get_operator_vault_ticket( &mut self, operator: &Pubkey, @@ -450,6 +455,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn do_ncn_cooldown_operator( &mut self, ncn_root: &NcnRoot, @@ -568,6 +574,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn do_operator_cooldown_ncn( &mut self, operator_root: &OperatorRoot, @@ -637,6 +644,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn do_initialize_ncn_vault_slasher_ticket( &mut self, ncn_root: &NcnRoot, @@ -672,6 +680,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn do_warmup_ncn_vault_slasher_ticket( &mut self, ncn_root: &NcnRoot, @@ -848,6 +857,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn ncn_set_admin( &mut self, ncn: &Pubkey, @@ -870,6 +880,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn operator_set_admin( &mut self, operator: &Pubkey, @@ -892,6 +903,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn operator_set_secondary_admin( &mut self, operator: &Pubkey, @@ -970,6 +982,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn operator_set_fee( &mut self, config: &Pubkey, @@ -994,6 +1007,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn ncn_delegate_token_account( &mut self, ncn_pubkey: &Pubkey, @@ -1021,6 +1035,7 @@ impl RestakingProgramClient { .await } + #[allow(dead_code)] pub async fn operator_delegate_token_account( &mut self, operator_pubkey: &Pubkey, @@ -1074,6 +1089,7 @@ impl RestakingProgramClient { Ok(()) } + #[allow(dead_code)] pub async fn set_config_admin( &mut self, config: &Pubkey, @@ -1098,6 +1114,7 @@ impl RestakingProgramClient { #[track_caller] #[inline(always)] +#[allow(dead_code)] pub fn assert_restaking_error( test_error: Result, restaking_error: RestakingError, diff --git a/integration_tests/tests/fixtures/test_builder.rs b/integration_tests/tests/fixtures/test_builder.rs index 74b03b6..e1d181e 100644 --- a/integration_tests/tests/fixtures/test_builder.rs +++ b/integration_tests/tests/fixtures/test_builder.rs @@ -1,29 +1,14 @@ use std::fmt::{Debug, Formatter}; -use jito_restaking_core::{ - config::Config, - ncn_vault_ticket::{self, NcnVaultTicket}, -}; +use jito_restaking_core::{config::Config, ncn_vault_ticket::NcnVaultTicket}; use jito_vault_core::vault_ncn_ticket::VaultNcnTicket; -use jito_vault_sdk::inline_mpl_token_metadata; use solana_program::{ clock::Clock, native_token::sol_to_lamports, pubkey::Pubkey, system_instruction::transfer, }; use solana_program_test::{processor, BanksClientError, ProgramTest, ProgramTestContext}; -use solana_sdk::{ - commitment_config::CommitmentLevel, - signature::{Keypair, Signer}, - transaction::Transaction, -}; -use spl_associated_token_account::{ - get_associated_token_address, instruction::create_associated_token_account_idempotent, -}; +use solana_sdk::{commitment_config::CommitmentLevel, signature::Signer, transaction::Transaction}; -use super::{ - restaking_client::{self, NcnRoot}, - tip_router_client::TipRouterClient, - vault_client, -}; +use super::{restaking_client::NcnRoot, tip_router_client::TipRouterClient}; use crate::fixtures::{ restaking_client::{OperatorRoot, RestakingProgramClient}, vault_client::{VaultProgramClient, VaultRoot}, @@ -37,6 +22,8 @@ pub struct TestNcn { } //TODO implement for more fine-grained relationship control +#[allow(dead_code)] + pub struct TestNcnNode { pub ncn_root: NcnRoot, pub operator_root: OperatorRoot, @@ -124,6 +111,7 @@ impl TestBuilder { ) } + #[allow(dead_code)] pub async fn transfer(&mut self, to: &Pubkey, sol: f64) -> Result<(), BanksClientError> { let blockhash = self.context.banks_client.get_latest_blockhash().await?; self.context diff --git a/integration_tests/tests/fixtures/tip_router_client.rs b/integration_tests/tests/fixtures/tip_router_client.rs index dc6cae5..e589d5e 100644 --- a/integration_tests/tests/fixtures/tip_router_client.rs +++ b/integration_tests/tests/fixtures/tip_router_client.rs @@ -15,7 +15,7 @@ use jito_tip_router_core::{ epoch_snapshot::{EpochSnapshot, OperatorSnapshot}, error::TipRouterError, ncn_config::NcnConfig, - tracked_mints::{self, TrackedMints}, + tracked_mints::TrackedMints, weight_table::WeightTable, }; use jito_vault_core::{ @@ -112,6 +112,7 @@ impl TipRouterClient { Ok(*TrackedMints::try_from_slice_unchecked(tracked_mints.data.as_slice()).unwrap()) } + #[allow(dead_code)] pub async fn get_weight_table( &mut self, ncn: Pubkey, @@ -142,6 +143,7 @@ impl TipRouterClient { Ok(*account) } + #[allow(dead_code)] pub async fn get_operator_snapshot( &mut self, operator: Pubkey, diff --git a/integration_tests/tests/fixtures/vault_client.rs b/integration_tests/tests/fixtures/vault_client.rs index 1103900..70eab1f 100644 --- a/integration_tests/tests/fixtures/vault_client.rs +++ b/integration_tests/tests/fixtures/vault_client.rs @@ -1,6 +1,5 @@ use std::{fmt, fmt::Debug}; -use borsh::BorshDeserialize; use jito_bytemuck::AccountDeserialize; use jito_restaking_core::{ ncn_vault_slasher_ticket::NcnVaultSlasherTicket, ncn_vault_ticket::NcnVaultTicket, @@ -69,6 +68,7 @@ impl Debug for VaultRoot { } #[derive(Debug)] +#[allow(dead_code)] pub struct VaultStakerWithdrawalTicketRoot { pub base: Pubkey, } @@ -112,6 +112,7 @@ impl VaultProgramClient { Ok(*Vault::try_from_slice_unchecked(account.data.as_slice())?) } + #[allow(dead_code)] pub async fn get_vault_ncn_ticket( &mut self, vault: &Pubkey, @@ -124,6 +125,7 @@ impl VaultProgramClient { )?) } + #[allow(dead_code)] pub async fn get_vault_operator_delegation( &mut self, vault: &Pubkey, @@ -141,6 +143,7 @@ impl VaultProgramClient { )?) } + #[allow(dead_code)] pub async fn get_vault_staker_withdrawal_ticket( &mut self, vault: &Pubkey, @@ -160,6 +163,7 @@ impl VaultProgramClient { Ok(withdrawal_ticket) } + #[allow(dead_code)] pub async fn get_vault_ncn_slasher_ticket( &mut self, vault: &Pubkey, @@ -203,6 +207,7 @@ impl VaultProgramClient { )?) } + #[allow(dead_code)] pub async fn get_vault_update_state_tracker( &mut self, vault: &Pubkey, @@ -253,6 +258,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn setup_config_and_vault( &mut self, deposit_fee_bps: u16, @@ -355,6 +361,7 @@ impl VaultProgramClient { Ok(()) } + #[allow(dead_code)] pub async fn set_capacity( &mut self, config: &Pubkey, @@ -507,6 +514,7 @@ impl VaultProgramClient { Ok(()) } + #[allow(dead_code)] pub async fn do_initialize_vault_ncn_slasher_ticket( &mut self, vault_root: &VaultRoot, @@ -543,6 +551,7 @@ impl VaultProgramClient { Ok(()) } + #[allow(dead_code)] pub async fn do_warmup_vault_ncn_slasher_ticket( &mut self, vault_root: &VaultRoot, @@ -717,6 +726,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn delegate_token_account( &mut self, config: &Pubkey, @@ -746,6 +756,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn set_admin( &mut self, config: &Pubkey, @@ -769,6 +780,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn set_secondary_admin( &mut self, config: &Pubkey, @@ -794,6 +806,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn set_fees( &mut self, config: &Pubkey, @@ -821,6 +834,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn set_program_fee( &mut self, config_admin: &Keypair, @@ -841,6 +855,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn do_enqueue_withdrawal( &mut self, vault_root: &VaultRoot, @@ -885,6 +900,7 @@ impl VaultProgramClient { }) } + #[allow(dead_code)] pub async fn do_cooldown_delegation( &mut self, vault_root: &VaultRoot, @@ -985,6 +1001,7 @@ impl VaultProgramClient { Ok(()) } + #[allow(dead_code)] pub async fn do_crank_vault_update_state_tracker( &mut self, vault: &Pubkey, @@ -1143,6 +1160,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn do_burn_withdrawal_ticket( &mut self, vault_root: &VaultRoot, @@ -1365,6 +1383,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn create_token_metadata( &mut self, vault: &Pubkey, @@ -1397,6 +1416,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn update_token_metadata( &mut self, vault: &Pubkey, @@ -1548,6 +1568,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn get_reward_fee_token_account( &mut self, vault: &Pubkey, @@ -1567,6 +1588,7 @@ impl VaultProgramClient { Ok(SPLTokenAccount::unpack(&account.data).unwrap()) } + #[allow(dead_code)] pub async fn create_and_fund_reward_vault( &mut self, vault: &Pubkey, @@ -1611,6 +1633,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn set_program_fee_wallet( &mut self, program_fee_admin: &Keypair, @@ -1631,6 +1654,7 @@ impl VaultProgramClient { .await } + #[allow(dead_code)] pub async fn set_is_paused( &mut self, vault: &Pubkey, @@ -1653,7 +1677,8 @@ impl VaultProgramClient { .await } - pub async fn set_config_admin( + #[allow(dead_code)] + pub async fn set_confsig_admin( &mut self, config: &Pubkey, old_admin: &Keypair, @@ -1677,6 +1702,7 @@ impl VaultProgramClient { #[inline(always)] #[track_caller] +#[allow(dead_code)] pub fn assert_vault_error(test_error: Result, vault_error: VaultError) { assert!(test_error.is_err()); assert_eq!( From 2e6a419fa84d59892de7badc490d86e3468c019c Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 19 Nov 2024 13:08:47 -0500 Subject: [PATCH 25/28] Force new blockhash on airdrop --- .../tests/fixtures/restaking_client.rs | 14 ++++++++++++-- .../tests/fixtures/tip_router_client.rs | 13 +++++++++++-- integration_tests/tests/fixtures/vault_client.rs | 13 +++++++++++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/integration_tests/tests/fixtures/restaking_client.rs b/integration_tests/tests/fixtures/restaking_client.rs index c8e817e..227ede5 100644 --- a/integration_tests/tests/fixtures/restaking_client.rs +++ b/integration_tests/tests/fixtures/restaking_client.rs @@ -17,11 +17,12 @@ use jito_restaking_sdk::{ warmup_operator_vault_ticket, }, }; +use log::debug; use solana_program::{ instruction::InstructionError, native_token::sol_to_lamports, pubkey::Pubkey, system_instruction::transfer, }; -use solana_program_test::BanksClient; +use solana_program_test::{BanksClient, ProgramTestBanksClientExt}; use solana_sdk::{ commitment_config::CommitmentLevel, signature::{Keypair, Signer}, @@ -1064,6 +1065,10 @@ impl RestakingProgramClient { } pub async fn process_transaction(&mut self, tx: &Transaction) -> TestResult<()> { + debug!( + "Restaking Client processing transaction: {:?}", + tx.signatures[0] + ); self.banks_client .process_transaction_with_preflight_and_commitment( tx.clone(), @@ -1075,13 +1080,18 @@ impl RestakingProgramClient { pub async fn airdrop(&mut self, to: &Pubkey, sol: f64) -> TestResult<()> { let blockhash = self.banks_client.get_latest_blockhash().await?; + let new_blockhash = self + .banks_client + .get_new_latest_blockhash(&blockhash) + .await + .unwrap(); self.banks_client .process_transaction_with_preflight_and_commitment( Transaction::new_signed_with_payer( &[transfer(&self.payer.pubkey(), to, sol_to_lamports(sol))], Some(&self.payer.pubkey()), &[&self.payer], - blockhash, + new_blockhash, ), CommitmentLevel::Processed, ) diff --git a/integration_tests/tests/fixtures/tip_router_client.rs b/integration_tests/tests/fixtures/tip_router_client.rs index e589d5e..8b09ed5 100644 --- a/integration_tests/tests/fixtures/tip_router_client.rs +++ b/integration_tests/tests/fixtures/tip_router_client.rs @@ -25,7 +25,7 @@ use solana_program::{ instruction::InstructionError, native_token::sol_to_lamports, pubkey::Pubkey, system_instruction::transfer, }; -use solana_program_test::BanksClient; +use solana_program_test::{BanksClient, ProgramTestBanksClientExt}; use solana_sdk::{ clock::Clock, commitment_config::CommitmentLevel, @@ -51,6 +51,10 @@ impl TipRouterClient { } pub async fn process_transaction(&mut self, tx: &Transaction) -> TestResult<()> { + println!( + "Tip Router Client processing transaction: {:?}", + tx.signatures[0] + ); self.banks_client .process_transaction_with_preflight_and_commitment( tx.clone(), @@ -62,13 +66,18 @@ impl TipRouterClient { pub async fn airdrop(&mut self, to: &Pubkey, sol: f64) -> TestResult<()> { let blockhash = self.banks_client.get_latest_blockhash().await?; + let new_blockhash = self + .banks_client + .get_new_latest_blockhash(&blockhash) + .await + .unwrap(); self.banks_client .process_transaction_with_preflight_and_commitment( Transaction::new_signed_with_payer( &[transfer(&self.payer.pubkey(), to, sol_to_lamports(sol))], Some(&self.payer.pubkey()), &[&self.payer], - blockhash, + new_blockhash, ), CommitmentLevel::Processed, ) diff --git a/integration_tests/tests/fixtures/vault_client.rs b/integration_tests/tests/fixtures/vault_client.rs index 70eab1f..5ad1f95 100644 --- a/integration_tests/tests/fixtures/vault_client.rs +++ b/integration_tests/tests/fixtures/vault_client.rs @@ -29,7 +29,7 @@ use solana_program::{ rent::Rent, system_instruction::{create_account, transfer}, }; -use solana_program_test::{BanksClient, BanksClientError}; +use solana_program_test::{BanksClient, BanksClientError, ProgramTestBanksClientExt}; use solana_sdk::{ commitment_config::CommitmentLevel, instruction::InstructionError, @@ -1447,6 +1447,10 @@ impl VaultProgramClient { } async fn _process_transaction(&mut self, tx: &Transaction) -> Result<(), TestError> { + println!( + "Vault Client processing transaction: {:?}", + tx.signatures[0] + ); self.banks_client .process_transaction_with_preflight_and_commitment( tx.clone(), @@ -1458,13 +1462,18 @@ impl VaultProgramClient { pub async fn airdrop(&mut self, to: &Pubkey, sol: f64) -> Result<(), TestError> { let blockhash = self.banks_client.get_latest_blockhash().await?; + let new_blockhash = self + .banks_client + .get_new_latest_blockhash(&blockhash) + .await + .map_err(|e| e.into())?; self.banks_client .process_transaction_with_preflight_and_commitment( Transaction::new_signed_with_payer( &[transfer(&self.payer.pubkey(), to, sol_to_lamports(sol))], Some(&self.payer.pubkey()), &[&self.payer], - blockhash, + new_blockhash, ), CommitmentLevel::Processed, ) From d8f975e72c0369cecea2506af3ce9ce0a6000091 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 19 Nov 2024 13:10:06 -0500 Subject: [PATCH 26/28] Rm prints --- integration_tests/tests/fixtures/restaking_client.rs | 4 ---- integration_tests/tests/fixtures/tip_router_client.rs | 4 ---- integration_tests/tests/fixtures/vault_client.rs | 4 ---- 3 files changed, 12 deletions(-) diff --git a/integration_tests/tests/fixtures/restaking_client.rs b/integration_tests/tests/fixtures/restaking_client.rs index 227ede5..d85d692 100644 --- a/integration_tests/tests/fixtures/restaking_client.rs +++ b/integration_tests/tests/fixtures/restaking_client.rs @@ -1065,10 +1065,6 @@ impl RestakingProgramClient { } pub async fn process_transaction(&mut self, tx: &Transaction) -> TestResult<()> { - debug!( - "Restaking Client processing transaction: {:?}", - tx.signatures[0] - ); self.banks_client .process_transaction_with_preflight_and_commitment( tx.clone(), diff --git a/integration_tests/tests/fixtures/tip_router_client.rs b/integration_tests/tests/fixtures/tip_router_client.rs index 8b09ed5..c4dea87 100644 --- a/integration_tests/tests/fixtures/tip_router_client.rs +++ b/integration_tests/tests/fixtures/tip_router_client.rs @@ -51,10 +51,6 @@ impl TipRouterClient { } pub async fn process_transaction(&mut self, tx: &Transaction) -> TestResult<()> { - println!( - "Tip Router Client processing transaction: {:?}", - tx.signatures[0] - ); self.banks_client .process_transaction_with_preflight_and_commitment( tx.clone(), diff --git a/integration_tests/tests/fixtures/vault_client.rs b/integration_tests/tests/fixtures/vault_client.rs index 5ad1f95..b065ab5 100644 --- a/integration_tests/tests/fixtures/vault_client.rs +++ b/integration_tests/tests/fixtures/vault_client.rs @@ -1447,10 +1447,6 @@ impl VaultProgramClient { } async fn _process_transaction(&mut self, tx: &Transaction) -> Result<(), TestError> { - println!( - "Vault Client processing transaction: {:?}", - tx.signatures[0] - ); self.banks_client .process_transaction_with_preflight_and_commitment( tx.clone(), From c642cfe0400c9b4ef410759509b0e915e912a4d2 Mon Sep 17 00:00:00 2001 From: Evan Batsell Date: Tue, 19 Nov 2024 13:21:03 -0500 Subject: [PATCH 27/28] Last fixes --- integration_tests/tests/fixtures/restaking_client.rs | 1 - integration_tests/tests/fixtures/vault_client.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/integration_tests/tests/fixtures/restaking_client.rs b/integration_tests/tests/fixtures/restaking_client.rs index d85d692..d914a42 100644 --- a/integration_tests/tests/fixtures/restaking_client.rs +++ b/integration_tests/tests/fixtures/restaking_client.rs @@ -17,7 +17,6 @@ use jito_restaking_sdk::{ warmup_operator_vault_ticket, }, }; -use log::debug; use solana_program::{ instruction::InstructionError, native_token::sol_to_lamports, pubkey::Pubkey, system_instruction::transfer, diff --git a/integration_tests/tests/fixtures/vault_client.rs b/integration_tests/tests/fixtures/vault_client.rs index b065ab5..73074ce 100644 --- a/integration_tests/tests/fixtures/vault_client.rs +++ b/integration_tests/tests/fixtures/vault_client.rs @@ -1462,7 +1462,7 @@ impl VaultProgramClient { .banks_client .get_new_latest_blockhash(&blockhash) .await - .map_err(|e| e.into())?; + .unwrap(); self.banks_client .process_transaction_with_preflight_and_commitment( Transaction::new_signed_with_payer( From a3c5d7675cb344a66977141329347ca25f46e3fd Mon Sep 17 00:00:00 2001 From: Christian Krueger Date: Tue, 19 Nov 2024 12:22:13 -0600 Subject: [PATCH 28/28] fixed tests --- .config/nextest.toml | 2 +- integration_tests/tests/fixtures/restaking_client.rs | 1 - integration_tests/tests/fixtures/vault_client.rs | 3 ++- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.config/nextest.toml b/.config/nextest.toml index 7544d59..569e91a 100644 --- a/.config/nextest.toml +++ b/.config/nextest.toml @@ -1,5 +1,5 @@ [profile.default] retries = { backoff = "exponential", count = 5, delay = "1s", jitter = true, max-delay = "10s" } -test-threads = 1 +test-threads = "num-cpus" threads-required = 1 fail-fast = false \ No newline at end of file diff --git a/integration_tests/tests/fixtures/restaking_client.rs b/integration_tests/tests/fixtures/restaking_client.rs index d85d692..d914a42 100644 --- a/integration_tests/tests/fixtures/restaking_client.rs +++ b/integration_tests/tests/fixtures/restaking_client.rs @@ -17,7 +17,6 @@ use jito_restaking_sdk::{ warmup_operator_vault_ticket, }, }; -use log::debug; use solana_program::{ instruction::InstructionError, native_token::sol_to_lamports, pubkey::Pubkey, system_instruction::transfer, diff --git a/integration_tests/tests/fixtures/vault_client.rs b/integration_tests/tests/fixtures/vault_client.rs index b065ab5..709c271 100644 --- a/integration_tests/tests/fixtures/vault_client.rs +++ b/integration_tests/tests/fixtures/vault_client.rs @@ -1462,7 +1462,8 @@ impl VaultProgramClient { .banks_client .get_new_latest_blockhash(&blockhash) .await - .map_err(|e| e.into())?; + .unwrap(); + self.banks_client .process_transaction_with_preflight_and_commitment( Transaction::new_signed_with_payer(