Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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
3 changes: 2 additions & 1 deletion controller/core/src/instructions/protocol_fee/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod set_protocol_fee;
pub mod set_protocol_fee_beneficiary;
pub mod withdraw_protocol_fees;
pub mod v1;
pub mod v2;
1 change: 1 addition & 0 deletions controller/core/src/instructions/protocol_fee/v1/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod withdraw_protocol_fees;
1 change: 1 addition & 0 deletions controller/core/src/instructions/protocol_fee/v2/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod withdraw_protocol_fees;
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use generic_array_struct::generic_array_struct;

use crate::instructions::generic::DiscmOnlyIxData;

// Accounts

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

/// The pool's protocol fee beneficiary
pub beneficiary: T,

/// INF token account to withdraw unclaimed protocol fees to
pub withdraw_to: T,

/// INF token mint
pub inf_mint: T,

/// INF token program
pub token_program: T,
}

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

pub type WithdrawProtocolFeesV2IxKeys<'a> = WithdrawProtocolFeesV2IxAccs<&'a [u8; 32]>;

pub type WithdrawProtocolFeesV2IxKeysOwned = WithdrawProtocolFeesV2IxAccs<[u8; 32]>;

pub type WithdrawProtocolFeesV2IxAccFlags = WithdrawProtocolFeesV2IxAccs<bool>;

pub const WITHDRAW_PROTOCOL_FEES_V2_IX_IS_WRITER: WithdrawProtocolFeesV2IxAccFlags =
WithdrawProtocolFeesV2IxAccFlags::memset(false)
.const_with_pool_state(true)
.const_with_withdraw_to(true)
.const_with_inf_mint(true);

pub const WITHDRAW_PROTOCOL_FEES_V2_IX_IS_SIGNER: WithdrawProtocolFeesV2IxAccFlags =
WithdrawProtocolFeesV2IxAccFlags::memset(false).const_with_beneficiary(true);

// Data

pub const WITHDRAW_PROTOCOL_FEES_V2_IX_DISCM: u8 = 25;

pub type WithdrawProtocolFeesV2IxData = DiscmOnlyIxData<WITHDRAW_PROTOCOL_FEES_V2_IX_DISCM>;

pub const WITHDRAW_PROTOCOL_FEES_V2_IX_DATA_LEN: usize = WithdrawProtocolFeesV2IxData::DATA_LEN;
3 changes: 2 additions & 1 deletion controller/program/src/instructions/protocol_fee/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod set_protocol_fee;
pub mod set_protocol_fee_beneficiary;
pub mod withdraw_protocol_fee;
pub mod v1;
pub mod v2;
1 change: 1 addition & 0 deletions controller/program/src/instructions/protocol_fee/v1/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod withdraw_protocol_fees;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use inf1_ctl_jiminy::{
account_utils::pool_state_v2_checked,
err::Inf1CtlErr,
instructions::protocol_fee::withdraw_protocol_fees::{
instructions::protocol_fee::v1::withdraw_protocol_fees::{
NewWithdrawProtocolFeesIxAccsBuilder, WithdrawProtocolFeesIxAccs,
WithdrawProtocolFeesIxData, WITHDRAW_PROTOCOL_FEES_IX_IS_SIGNER,
},
Expand Down
1 change: 1 addition & 0 deletions controller/program/src/instructions/protocol_fee/v2/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod withdraw_protocol_fees;
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use inf1_ctl_jiminy::{
account_utils::{pool_state_v2_checked, pool_state_v2_checked_mut},
err::Inf1CtlErr,
instructions::protocol_fee::v2::withdraw_protocol_fees::{
NewWithdrawProtocolFeesV2IxAccsBuilder, WithdrawProtocolFeesV2IxAccs,
WITHDRAW_PROTOCOL_FEES_V2_IX_IS_SIGNER,
},
keys::POOL_STATE_ID,
pda_onchain::POOL_STATE_SIGNER,
program_err::Inf1CtlCustomProgErr,
svc::InfCalc,
typedefs::pool_sv::PoolSvLamports,
};
use jiminy_cpi::{
account::{Abr, AccountHandle},
program_error::{ProgramError, NOT_ENOUGH_ACCOUNT_KEYS},
Cpi,
};
use jiminy_sysvar_clock::Clock;
use sanctum_spl_token_jiminy::{
instructions::mint_to::mint_to_ix_account_handle_perms,
sanctum_spl_token_core::instructions::mint_to::{MintToIxData, NewMintToIxAccsBuilder},
};

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

type WithdrawProtocolFeesV2IxAccounts<'acc> = WithdrawProtocolFeesV2IxAccs<AccountHandle<'acc>>;

#[inline]
pub fn withdraw_protocol_fees_v2_checked<'acc>(
abr: &Abr,
accs: &[AccountHandle<'acc>],
) -> Result<WithdrawProtocolFeesV2IxAccounts<'acc>, ProgramError> {
let accs = accs.first_chunk().ok_or(NOT_ENOUGH_ACCOUNT_KEYS)?;
let accs = WithdrawProtocolFeesV2IxAccs(*accs);

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

let expected_pks = NewWithdrawProtocolFeesV2IxAccsBuilder::start()
.with_pool_state(&POOL_STATE_ID)
.with_beneficiary(&pool.protocol_fee_beneficiary)
.with_inf_mint(&pool.lp_token_mint)
.with_token_program(mint_acc.owner())
// Free: the beneficiary is free to specify whatever INF token account to withdraw to
// In the case of an invalid INF token acc, token prog mint_to CPI will fail
.with_withdraw_to(abr.get(*accs.withdraw_to()).key())
.build();
verify_pks(abr, &accs.0, &expected_pks.0)?;

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

verify_not_rebalancing_and_not_disabled(pool)?;

Ok(accs)
}

#[inline]
pub fn process_withdraw_protocol_fees_v2(
abr: &mut Abr,
cpi: &mut Cpi,
accs: WithdrawProtocolFeesV2IxAccounts,
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)?;

let protocol_fee_lamports = pool.protocol_fee_lamports;

if protocol_fee_lamports == 0 {
return Ok(());
}

let pool_lamports = PoolSvLamports::from_pool_state_v2(pool);
let inf_token_supply = checked_mint_of(abr.get(*accs.inf_mint()))?.supply();

let inf_calc = InfCalc {
pool_lamports,
mint_supply: inf_token_supply,
};

let inf_to_mint = inf_calc
.sol_to_inf(protocol_fee_lamports)
.ok_or(Inf1CtlCustomProgErr(Inf1CtlErr::MathError))?;

if inf_to_mint == 0 {
return Ok(());
}

cpi.invoke_signed_handle(
abr,
*accs.token_program(),
MintToIxData::new(inf_to_mint).as_buf(),
mint_to_ix_account_handle_perms(
NewMintToIxAccsBuilder::start()
.with_auth(*accs.pool_state())
.with_mint(*accs.inf_mint())
.with_to(*accs.withdraw_to())
.build(),
),
&[POOL_STATE_SIGNER],
)?;

let pool = pool_state_v2_checked_mut(abr.get_mut(*accs.pool_state()))?;
pool.protocol_fee_lamports = 0;

Ok(())
}
15 changes: 13 additions & 2 deletions controller/program/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ use inf1_ctl_jiminy::instructions::{
protocol_fee::{
set_protocol_fee::SET_PROTOCOL_FEE_IX_DISCM,
set_protocol_fee_beneficiary::SET_PROTOCOL_FEE_BENEFICIARY_IX_DISCM,
withdraw_protocol_fees::WITHDRAW_PROTOCOL_FEES_IX_DISCM,
v1::withdraw_protocol_fees::WITHDRAW_PROTOCOL_FEES_IX_DISCM,
v2::withdraw_protocol_fees::WITHDRAW_PROTOCOL_FEES_V2_IX_DISCM,
},
rebalance::{
end::END_REBALANCE_IX_DISCM,
Expand Down Expand Up @@ -80,9 +81,12 @@ use crate::{
set_protocol_fee_beneficiary::{
process_set_protocol_fee_beneficiary, set_protocol_fee_beneficiary_accs_checked,
},
withdraw_protocol_fee::{
v1::withdraw_protocol_fees::{
process_withdraw_protocol_fees, withdraw_protocol_fees_checked,
},
v2::withdraw_protocol_fees::{
process_withdraw_protocol_fees_v2, withdraw_protocol_fees_v2_checked,
},
},
rebalance::{
end::process_end_rebalance,
Expand Down Expand Up @@ -268,6 +272,13 @@ 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 Down
7 changes: 4 additions & 3 deletions controller/program/tests/tests/protocol_fee/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod set_protocol_fee;
mod set_protocol_fee_beneficiary;
mod withdraw_protocol_fees;
pub mod set_protocol_fee;
pub mod set_protocol_fee_beneficiary;
pub mod v1;
pub mod v2;
1 change: 1 addition & 0 deletions controller/program/tests/tests/protocol_fee/v1/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod withdraw_protocol_fees;
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use generic_array_struct::generic_array_struct;
use inf1_ctl_jiminy::{
accounts::pool_state::{PoolStateV2, PoolStateV2Addrs, PoolStateV2FtaVals},
err::Inf1CtlErr,
instructions::protocol_fee::withdraw_protocol_fees::{
instructions::protocol_fee::v1::withdraw_protocol_fees::{
NewWithdrawProtocolFeesIxAccsBuilder, WithdrawProtocolFeesIxAccsBuilder,
WithdrawProtocolFeesIxData, WithdrawProtocolFeesIxKeysOwned,
WITHDRAW_PROTOCOL_FEES_IX_ACCS_IDX_BENEFICIARY,
Expand Down
1 change: 1 addition & 0 deletions controller/program/tests/tests/protocol_fee/v2/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mod withdraw_protocol_fees;
Loading