-
Notifications
You must be signed in to change notification settings - Fork 0
/
extend_stake.rs
113 lines (102 loc) · 3.74 KB
/
extend_stake.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::{clock_unix_timestamp, cpi_instructions, Stake};
use anchor_lang::prelude::*;
use mplx_staking_states::{
error::MplStakingError,
registrar_seeds,
state::{LockupKind, LockupPeriod},
};
/// Prolongs the deposit
///
/// The stake will be extended with the same lockup period as it was previously in case it's not
/// expired. If the deposit has expired, it can be extended with any LockupPeriod.
/// The deposit entry must have been initialized with create_deposit_entry.
///
/// `deposit_entry_index`: Index of the deposit entry.
pub fn extend_stake(
ctx: Context<Stake>,
source_deposit_entry_index: u8,
target_deposit_entry_index: u8,
new_lockup_period: LockupPeriod,
additional_amount: u64,
) -> Result<()> {
let registrar = ctx.accounts.registrar.load()?;
require!(
registrar.reward_pool == ctx.accounts.reward_pool.key(),
MplStakingError::InvalidRewardPool
);
let curr_ts = clock_unix_timestamp();
let voter = &mut ctx.accounts.voter.load_mut()?;
let source = voter.active_deposit_mut(source_deposit_entry_index)?;
let source_mint_idx = source.voting_mint_config_idx;
let source_available_tokens = source.amount_unlocked();
require!(
source.lockup.kind == LockupKind::None,
MplStakingError::LockingIsForbidded
);
source.amount_deposited_native = source
.amount_deposited_native
.checked_sub(additional_amount)
.ok_or(MplStakingError::ArithmeticOverflow)?;
let target = voter.active_deposit_mut(target_deposit_entry_index)?;
require_gte!(
source_available_tokens,
additional_amount,
MplStakingError::InsufficientUnlockedTokens
);
require!(
target.lockup.period != LockupPeriod::None && target.lockup.kind != LockupKind::None,
MplStakingError::ExtendDepositIsNotAllowed
);
let start_ts = target.lockup.start_ts;
let target_basic_amount = target.amount_deposited_native;
let current_lockup_period = if target.lockup.expired(curr_ts) {
LockupPeriod::Flex
} else {
target.lockup.period
};
// different type of deposit is only allowed if
// the current deposit has expired
require!(
new_lockup_period >= current_lockup_period,
MplStakingError::ExtendDepositIsNotAllowed
);
// Check target compatibility
require_eq!(
target.voting_mint_config_idx,
source_mint_idx,
MplStakingError::InvalidMint
);
ctx.accounts.verify_delegate(target)?;
target.amount_deposited_native = target
.amount_deposited_native
.checked_add(additional_amount)
.ok_or(MplStakingError::ArithmeticOverflow)?;
target.lockup.start_ts = curr_ts;
target.lockup.end_ts = curr_ts
.checked_add(new_lockup_period.to_secs())
.ok_or(MplStakingError::InvalidTimestampArguments)?;
target.lockup.period = new_lockup_period;
let reward_pool = ctx.accounts.reward_pool.to_account_info();
let mining = ctx.accounts.deposit_mining.to_account_info();
let deposit_authority = ctx.accounts.registrar.to_account_info();
let delegate_mining = ctx.accounts.delegate_mining.to_account_info();
let signers_seeds = registrar_seeds!(®istrar);
let mining_owner = &ctx.accounts.voter_authority.key();
let delegate_wallet_addr = &ctx.accounts.delegate.key();
cpi_instructions::extend_stake(
ctx.accounts.rewards_program.to_account_info(),
reward_pool,
mining.to_account_info(),
deposit_authority,
delegate_mining,
current_lockup_period,
new_lockup_period,
start_ts,
target_basic_amount,
additional_amount,
mining_owner,
signers_seeds,
delegate_wallet_addr,
)?;
Ok(())
}