Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions controller/core/src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ pub mod generic;
pub mod liquidity;
pub mod protocol_fee;
pub mod rebalance;
pub mod rps;
pub mod swap;
pub mod sync_sol_value;
1 change: 1 addition & 0 deletions controller/core/src/instructions/rps/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod set_rps;
70 changes: 70 additions & 0 deletions controller/core/src/instructions/rps/set_rps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use generic_array_struct::generic_array_struct;

use crate::instructions::internal_utils::caba;

// Accounts

#[generic_array_struct(builder pub)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct SetRpsIxAccs<T> {
/// The pool's state singleton PDA
pub pool_state: T,

/// The pool's RPS authority
pub rps_auth: T,
}

impl<T: Copy> SetRpsIxAccs<T> {
#[inline]
pub const fn memset(val: T) -> Self {
Self([val; SET_RPS_IX_ACCS_LEN])
}
}

pub type SetRpsIxKeys<'a> = SetRpsIxAccs<&'a [u8; 32]>;

pub type SetRpsIxKeysOwned = SetRpsIxAccs<[u8; 32]>;

pub type SetRpsIxAccFlags = SetRpsIxAccs<bool>;

pub const SET_RPS_IX_IS_WRITER: SetRpsIxAccFlags =
SetRpsIxAccFlags::memset(false).const_with_pool_state(true);

pub const SET_RPS_IX_IS_SIGNER: SetRpsIxAccFlags =
SetRpsIxAccFlags::memset(false).const_with_rps_auth(true);

// Data

pub const SET_RPS_IX_DISCM: u8 = 26;

pub const SET_RPS_IX_DATA_LEN: usize = 9;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct SetRpsIxData([u8; SET_RPS_IX_DATA_LEN]);

impl SetRpsIxData {
#[inline]
pub const fn new(rps: u64) -> Self {
const A: usize = SET_RPS_IX_DATA_LEN;

let mut d = [0u8; A];

d = caba::<A, 0, 1>(d, &[SET_RPS_IX_DISCM]);
d = caba::<A, 1, 8>(d, &rps.to_le_bytes());

Self(d)
}

#[inline]
pub const fn as_buf(&self) -> &[u8; SET_RPS_IX_DATA_LEN] {
&self.0
}

/// Returns `rps` arg, the new RPS to set to
#[inline]
pub const fn parse_no_discm(data: &[u8; 8]) -> u64 {
u64::from_le_bytes(*data)
}
}
1 change: 1 addition & 0 deletions controller/program/src/instructions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ pub mod admin;
pub mod disable_pool;
pub mod protocol_fee;
pub mod rebalance;
pub mod rps;
pub mod swap;
pub mod sync_sol_value;
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub fn withdraw_protocol_fees_v2_checked<'acc>(
pub fn process_withdraw_protocol_fees_v2(
abr: &mut Abr,
cpi: &mut Cpi,
accs: WithdrawProtocolFeesV2IxAccounts,
accs: &WithdrawProtocolFeesV2IxAccounts,
clock: &Clock,
) -> Result<(), ProgramError> {
let pool = pool_state_v2_checked_mut(abr.get_mut(*accs.pool_state()))?;
Expand Down
1 change: 1 addition & 0 deletions controller/program/src/instructions/rps/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod set_rps;
67 changes: 67 additions & 0 deletions controller/program/src/instructions/rps/set_rps.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use inf1_ctl_jiminy::{
account_utils::{pool_state_v2_checked, pool_state_v2_checked_mut},
instructions::rps::set_rps::{
NewSetRpsIxAccsBuilder, SetRpsIxAccs, SetRpsIxData, SET_RPS_IX_IS_SIGNER,
},
keys::POOL_STATE_ID,
program_err::Inf1CtlCustomProgErr,
typedefs::{rps::Rps, uq0f63::UQ0F63},
};
use jiminy_cpi::{
account::{Abr, AccountHandle},
program_error::{ProgramError, INVALID_INSTRUCTION_DATA, NOT_ENOUGH_ACCOUNT_KEYS},
};
use jiminy_sysvar_clock::Clock;

use crate::verify::{verify_not_rebalancing_and_not_disabled, verify_pks, verify_signers};

type SetRpsIxAccounts<'acc> = SetRpsIxAccs<AccountHandle<'acc>>;

#[inline]
pub fn set_rps_checked<'acc>(
abr: &mut Abr,
accs: &[AccountHandle<'acc>],
ix_data_no_discm: &[u8],
) -> Result<(SetRpsIxAccounts<'acc>, u64), ProgramError> {
let accs = accs.first_chunk().ok_or(NOT_ENOUGH_ACCOUNT_KEYS)?;
let accs = SetRpsIxAccs(*accs);

let data: &[u8; 8] = ix_data_no_discm
.try_into()
.map_err(|_| INVALID_INSTRUCTION_DATA)?;
let new_rps_raw = SetRpsIxData::parse_no_discm(data);

// Validate raw RPS value
let uq = UQ0F63::new(new_rps_raw).map_err(|_| INVALID_INSTRUCTION_DATA)?;
let _new_rps = Rps::new(uq).map_err(|_| INVALID_INSTRUCTION_DATA)?;

let pool = pool_state_v2_checked(abr.get(*accs.pool_state()))?;

let expected_pks = NewSetRpsIxAccsBuilder::start()
.with_pool_state(&POOL_STATE_ID)
.with_rps_auth(&pool.rps_authority)
.build();
verify_pks(abr, &accs.0, &expected_pks.0)?;

verify_signers(abr, &accs.0, &SET_RPS_IX_IS_SIGNER.0)?;

verify_not_rebalancing_and_not_disabled(pool)?;

Ok((accs, new_rps_raw))
}

#[inline]
pub fn process_set_rps(
abr: &mut Abr,
accs: &SetRpsIxAccounts,
new_rps: u64,
clock: &Clock,
) -> Result<(), ProgramError> {
let pool = pool_state_v2_checked_mut(abr.get_mut(*accs.pool_state()))?;
pool.release_yield(clock.slot)
.map_err(Inf1CtlCustomProgErr)?;

pool.rps = new_rps;

Ok(())
}
23 changes: 16 additions & 7 deletions controller/program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use inf1_ctl_jiminy::instructions::{
set_rebal_auth::SET_REBAL_AUTH_IX_DISCM,
start::{StartRebalanceIxData, START_REBALANCE_IX_DISCM},
},
rps::set_rps::SET_RPS_IX_DISCM,
swap::{
parse_swap_ix_args,
v1::{exact_in::SWAP_EXACT_IN_IX_DISCM, exact_out::SWAP_EXACT_OUT_IX_DISCM},
Expand Down Expand Up @@ -88,6 +89,7 @@ use crate::{
set_rebal_auth::{process_set_rebal_auth, set_rebal_auth_accs_checked},
start::process_start_rebalance,
},
rps::set_rps::{process_set_rps, set_rps_checked},
swap::{
v1::{
add_liq_split_v1_accs_into_v2, conv_add_liq_args, conv_rem_liq_args,
Expand Down Expand Up @@ -281,13 +283,6 @@ fn process_ix(
let accs = set_rebal_auth_accs_checked(abr, accounts)?;
process_set_rebal_auth(abr, accs)
}
// v2 withdraw protocol fees
(&WITHDRAW_PROTOCOL_FEES_V2_IX_DISCM, _) => {
sol_log("WithdrawProtocolFeesV2");
let accs = withdraw_protocol_fees_v2_checked(abr, accounts)?;
let clock = Clock::write_to(&mut clock)?;
process_withdraw_protocol_fees_v2(abr, cpi, accs, clock)
}
// v2 swap
(&SWAP_EXACT_IN_V2_IX_DISCM, data) => {
sol_log("SwapExactInV2");
Expand All @@ -305,6 +300,20 @@ fn process_ix(
verify_swap_v2(abr, &accs, &args, clock)?;
process_swap_exact_out_v2(abr, cpi, &accs, &args, clock)
}
// v2 withdraw protocol fees
(&WITHDRAW_PROTOCOL_FEES_V2_IX_DISCM, _) => {
sol_log("WithdrawProtocolFeesV2");
let accs = withdraw_protocol_fees_v2_checked(abr, accounts)?;
let clock = Clock::write_to(&mut clock)?;
process_withdraw_protocol_fees_v2(abr, cpi, &accs, clock)
}
// v2 set rps
(&SET_RPS_IX_DISCM, data) => {
sol_log("SetRps");
let (accs, rps) = set_rps_checked(abr, accounts, data)?;
let clock = Clock::write_to(&mut clock)?;
process_set_rps(abr, &accs, rps, clock)
}
_ => Err(INVALID_INSTRUCTION_DATA.into()),
}
}
6 changes: 6 additions & 0 deletions controller/program/tests/common/pool_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::borrow::Borrow;
use inf1_ctl_jiminy::{
accounts::pool_state::PoolStateV2, sync_sol_val::SyncSolVal, typedefs::snap::NewSnapBuilder,
};
use inf1_svc_ag_core::calc::SvcCalcAg;
use inf1_svc_jiminy::traits::SolValCalc;

/// Calc, balance, sol value
Expand Down Expand Up @@ -44,3 +45,8 @@ where
pub fn assert_lp_solvent_invar(ps: &PoolStateV2) {
assert!(ps.total_sol_value >= ps.withheld_lamports + ps.protocol_fee_lamports);
}

/// Lookahead to after release_yield with no LST updates
pub fn header_lookahead_no_lsts(ps: PoolStateV2, curr_slot: u64) -> PoolStateV2 {
header_lookahead(ps, &[] as &[Cbs<SvcCalcAg>], curr_slot)
}
4 changes: 2 additions & 2 deletions controller/program/tests/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ mod admin;
mod disable_pool;
mod protocol_fee;
mod rebalance;
mod sync_sol_value;

mod rps;
mod swap;
mod sync_sol_value;
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use inf1_ctl_jiminy::{
svc::InfCalc,
typedefs::pool_sv::PoolSvLamports,
};
use inf1_svc_ag_core::{calc::SvcCalcAg, inf1_svc_lido_core::solido_legacy_core::TOKENKEG_PROGRAM};
use inf1_svc_ag_core::inf1_svc_lido_core::solido_legacy_core::TOKENKEG_PROGRAM;
use inf1_test_utils::{
acc_bef_aft, any_normal_pk, any_pool_state_v2, assert_diffs_pool_state_v2,
assert_jiminy_prog_err, assert_token_acc_diffs, keys_signer_writable_to_metas,
Expand All @@ -35,7 +35,7 @@ use sanctum_u64_ratio::Ratio;
use solana_instruction::Instruction;
use solana_pubkey::Pubkey;

use crate::common::{header_lookahead, Cbs, SVM};
use crate::common::{header_lookahead_no_lsts, SVM};
use jiminy_cpi::program_error::{ProgramError, INVALID_ARGUMENT, MISSING_REQUIRED_SIGNATURE};

const INF_MINT_ID: [u8; 32] = INF_MINT.to_bytes();
Expand All @@ -44,11 +44,6 @@ const INF_MINT_ID: [u8; 32] = INF_MINT.to_bytes();
/// when protocol_fee_lamports * inf_mint_supply
const SAFE_MUL_U64_MAX: u64 = u32::MAX as u64;

/// Lookahead to after release_yield with no LST updates
fn pool_state_header_lookahead(ps: PoolStateV2, curr_slot: u64) -> PoolStateV2 {
header_lookahead(ps, &[] as &[Cbs<SvcCalcAg>], curr_slot)
}

fn withdraw_protocol_fees_v2_ix(keys: &WithdrawProtocolFeesV2IxKeysOwned) -> Instruction {
let accounts = keys_signer_writable_to_metas(
keys.0.iter(),
Expand Down Expand Up @@ -120,8 +115,7 @@ fn withdraw_protocol_fees_v2_test(
})
};

let pool_state_bef =
pool_state_header_lookahead(pool_state_bef, svm.sysvars.clock.slot);
let pool_state_bef = header_lookahead_no_lsts(pool_state_bef, svm.sysvars.clock.slot);

let [withdraw_to_bef, withdraw_to_aft] = {
acc_bef_aft(&withdraw_to_pk, bef, &aft)
Expand Down
1 change: 1 addition & 0 deletions controller/program/tests/tests/rps/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod set_rps;
Loading