diff --git a/src/lib.rs b/src/lib.rs index 2d49f14..4dec7dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +use anchor_client::solana_sdk; pub use { crate::{pda::*, types::*}, anchor_lang::prelude::*, @@ -98,6 +99,13 @@ mod adrena_abi { pub(crate) fn claim_stakes(cx: Context) -> Result<()> { Ok(()) } + + pub(crate) fn finalize_locked_stake( + cx: Context, + params: FinalizeLockedStakeParams, + ) -> Result<()> { + Ok(()) + } } #[derive(Accounts)] @@ -589,3 +597,58 @@ pub(crate) struct ClaimStakes<'info> { /// CHECKS: only for CPI token_program: UncheckedAccount<'info>, } + +#[derive(Accounts)] +pub struct FinalizeLockedStake<'info> { + /// #1 + #[account(mut)] + pub caller: Signer<'info>, + /// #2 + #[account(mut)] + pub owner: AccountInfo<'info>, + /// #3 + pub transfer_authority: AccountInfo<'info>, + /// #4 + #[account(mut)] + pub user_staking: AccountLoader<'info, UserStaking>, + /// #5 + #[account(mut)] + pub staking: AccountLoader<'info, Staking>, + /// #6 + #[account(mut)] + pub cortex: AccountLoader<'info, Cortex>, + /// #7 + #[account(mut)] + pub lm_token_mint: AccountInfo<'info>, + /// #8 + #[account(mut)] + pub governance_token_mint: AccountInfo<'info>, + /// #9 + pub governance_realm: UncheckedAccount<'info>, + /// #10 + pub governance_realm_config: UncheckedAccount<'info>, + /// #11 + #[account(mut)] + pub governance_governing_token_holding: UncheckedAccount<'info>, + /// #12 + #[account(mut)] + pub governance_governing_token_owner_record: UncheckedAccount<'info>, + /// #13 + #[account(mut)] + pub stake_resolution_thread: UncheckedAccount<'info>, + /// #14 + #[account(address = SABLIER_THREAD_PROGRAM_ID)] + sablier_program: AccountInfo<'info>, + /// #15 + #[account(address = SPL_GOVERNANCE_PROGRAM_ID)] + governance_program: AccountInfo<'info>, + /// #16 + #[account(address = ADRENA_PROGRAM_ID)] + adrena_program: AccountInfo<'info>, + /// #17 + #[account(address = solana_sdk::system_program::ID)] + system_program: AccountInfo<'info>, + /// #18 + #[account(address = SPL_TOKEN_PROGRAM_ID)] + token_program: AccountInfo<'info>, +} diff --git a/src/types.rs b/src/types.rs index b74ff19..8b70086 100644 --- a/src/types.rs +++ b/src/types.rs @@ -35,6 +35,12 @@ pub struct LiquidateLongParams {} #[derive(AnchorSerialize, AnchorDeserialize)] pub struct LiquidateShortParams {} +#[derive(AnchorSerialize, AnchorDeserialize, Copy, Clone)] +pub struct FinalizeLockedStakeParams { + pub thread_id: u64, + pub early_exit: bool, +} + #[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Debug, Default, Pod, Zeroable)] #[repr(C)] pub struct LimitedString { @@ -603,3 +609,46 @@ pub struct LockedStake { pub _padding4: [u8; 7], pub genesis_claim_time: i64, } + +impl LockedStake { + pub const FEE_RATE_UPPER_CAP: u128 = 400_000_000; // 40% + pub const FEE_RATE_LOWER_CAP: u128 = 50_000_000; // 5% + + pub fn is_initialized(&self) -> bool { + self.amount > 0 + } + + pub fn is_genesis(&self) -> bool { + self.is_genesis != 0 + } + + pub fn is_resolved(&self) -> bool { + self.resolved != 0 + } + + pub fn is_early_exit(&self) -> bool { + self.early_exit != 0 + } + + pub fn is_established(&self) -> bool { + self.qualified_for_rewards_in_resolved_round_count >= 1 + } + + pub fn qualifies_for_rewards_from(&self, staking_round: &StakingRound) -> bool { + self.stake_time > 0 + && self.stake_time < staking_round.start_time + && (self.claim_time == 0 || self.claim_time < staking_round.start_time) + && staking_round.end_time <= self.end_time + && staking_round.start_time < self.end_time + } + + pub fn has_ended(&self, current_time: i64) -> anyhow::Result { + if self.stake_time == 0 { + anyhow::bail!("Invalid stake state"); + } + if !self.is_initialized() { + anyhow::bail!("Invalid stake state"); + } + Ok(self.end_time <= current_time) + } +}