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
use anchor_lang::prelude::*;
use jet_metadata::MarginAdapterMetadata;
use crate::adapter::{self, InvokeAdapter};
use crate::{events, ErrorCode, Liquidation, LiquidationState, MarginAccount, Valuation};
#[derive(Accounts)]
pub struct LiquidatorInvoke<'info> {
pub liquidator: Signer<'info>,
#[account(mut)]
pub liquidation: AccountLoader<'info, LiquidationState>,
#[account(mut,
has_one = liquidation,
has_one = liquidator)]
pub margin_account: AccountLoader<'info, MarginAccount>,
pub adapter_program: AccountInfo<'info>,
#[account(has_one = adapter_program)]
pub adapter_metadata: Account<'info, MarginAdapterMetadata>,
}
pub fn liquidator_invoke_handler<'info>(
ctx: Context<'_, '_, '_, 'info, LiquidatorInvoke<'info>>,
data: Vec<u8>,
) -> Result<()> {
let margin_account = &ctx.accounts.margin_account;
let start_value = margin_account.load()?.valuation()?;
emit!(events::LiquidatorInvokeBegin {
margin_account: ctx.accounts.margin_account.key(),
adapter_program: ctx.accounts.adapter_program.key(),
liquidator: ctx.accounts.liquidator.key(),
});
let events = adapter::invoke(
&InvokeAdapter {
margin_account: &ctx.accounts.margin_account,
adapter_program: &ctx.accounts.adapter_program,
accounts: ctx.remaining_accounts,
signed: true,
},
data,
)?;
for event in events {
event.emit();
}
let liquidation = &mut ctx.accounts.liquidation.load_mut()?.state;
let end_value = update_and_verify_liquidation(
&*ctx.accounts.margin_account.load()?,
liquidation,
start_value,
)?;
emit!(events::LiquidatorInvokeEnd {
liquidation_data: *liquidation,
valuation_summary: end_value.into(),
});
Ok(())
}
fn update_and_verify_liquidation(
margin_account: &MarginAccount,
liquidation: &mut Liquidation,
start_value: Valuation,
) -> Result<Valuation> {
let end_value = margin_account.valuation()?;
*liquidation.equity_change_mut() += end_value.equity - start_value.equity; if liquidation.equity_change() < &liquidation.min_equity_change() {
msg!(
"Illegal liquidation: net loss of {} equity which exceeds the min equity change of {}",
liquidation.equity_change(),
liquidation.min_equity_change()
);
err!(ErrorCode::LiquidationLostValue)
} else {
Ok(end_value)
}
}