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
use anchor_lang::prelude::*;
use jet_program_common::Number128;
use crate::{
events, ErrorCode, Liquidation, LiquidationState, MarginAccount,
LIQUIDATION_MAX_EQUITY_LOSS_BPS,
};
use jet_metadata::LiquidatorMetadata;
#[derive(Accounts)]
pub struct LiquidateBegin<'info> {
#[account(mut)]
pub margin_account: AccountLoader<'info, MarginAccount>,
#[account(mut)]
pub payer: Signer<'info>,
pub liquidator: Signer<'info>,
#[account(has_one = liquidator)]
pub liquidator_metadata: Account<'info, LiquidatorMetadata>,
#[account(
init,
seeds = [
b"liquidation",
margin_account.key().as_ref(),
liquidator.key().as_ref()
],
bump,
payer = payer,
space = 8 + std::mem::size_of::<LiquidationState>(),
)]
pub liquidation: AccountLoader<'info, LiquidationState>,
system_program: Program<'info, System>,
}
pub fn liquidate_begin_handler(ctx: Context<LiquidateBegin>) -> Result<()> {
let liquidation = &ctx.accounts.liquidation;
let liquidator = &ctx.accounts.liquidator;
let mut account = ctx.accounts.margin_account.load_mut()?;
account.verify_unhealthy_positions()?;
match account.liquidation {
liq if liq == liquidation.key() => {
unreachable!();
}
liq if liq == Pubkey::default() => {
account.start_liquidation(liquidation.key(), liquidator.key());
}
_ => {
return Err(ErrorCode::Liquidating.into());
}
}
let valuation = account.valuation()?;
let min_equity_change = (valuation.effective_collateral - valuation.required_collateral)
* Number128::from_bps(LIQUIDATION_MAX_EQUITY_LOSS_BPS);
let liquidation_state = LiquidationState {
state: Liquidation::new(Clock::get()?.unix_timestamp, min_equity_change),
};
*ctx.accounts.liquidation.load_init()? = liquidation_state;
emit!(events::LiquidationBegun {
margin_account: ctx.accounts.margin_account.key(),
liquidator: ctx.accounts.liquidator.key(),
liquidation: ctx.accounts.liquidation.key(),
liquidation_data: liquidation_state.state,
valuation_summary: valuation.into(),
});
Ok(())
}