percli_program/instructions/
withdraw_insurance.rs1use anchor_lang::prelude::*;
2use anchor_spl::token::{transfer_checked, Mint, Token, TokenAccount, TransferChecked};
3
4use crate::error::{from_risk_error, PercolatorError};
5use crate::instructions::events;
6use crate::state::{
7 engine_from_account_data, header_from_account_data, market_signer_seeds, MARKET_ACCOUNT_SIZE,
8};
9
10#[derive(Accounts)]
11pub struct WithdrawInsurance<'info> {
12 #[account(mut)]
13 pub authority: Signer<'info>,
14
15 #[account(
17 mut,
18 owner = crate::ID @ PercolatorError::AccountNotFound,
19 constraint = market.data_len() >= MARKET_ACCOUNT_SIZE @ PercolatorError::AccountNotFound,
20 )]
21 pub market: UncheckedAccount<'info>,
22
23 pub mint: Account<'info, Mint>,
24
25 #[account(
27 mut,
28 constraint = authority_token_account.owner == authority.key(),
29 constraint = authority_token_account.mint == mint.key(),
30 )]
31 pub authority_token_account: Account<'info, TokenAccount>,
32
33 #[account(
35 mut,
36 seeds = [b"vault", market.key().as_ref()],
37 bump,
38 constraint = vault.mint == mint.key(),
39 )]
40 pub vault: Account<'info, TokenAccount>,
41
42 pub token_program: Program<'info, Token>,
43}
44
45pub fn handler(ctx: Context<WithdrawInsurance>, amount: u64) -> Result<()> {
46 require!(amount > 0, PercolatorError::InsufficientBalance);
47
48 let market = &ctx.accounts.market;
49 let mut data = market.try_borrow_mut_data()?;
50
51 require!(
52 &data[0..8] == b"percmrkt",
53 PercolatorError::AccountNotFound
54 );
55
56 let header = header_from_account_data(&data)?;
57 require!(
58 header.authority == ctx.accounts.authority.key(),
59 PercolatorError::Unauthorized
60 );
61 require!(
62 header.mint == ctx.accounts.mint.key(),
63 PercolatorError::Unauthorized
64 );
65
66 let engine = engine_from_account_data(&mut data);
67 let clock = Clock::get()?;
68
69 engine
70 .withdraw_insurance(amount as u128, clock.slot)
71 .map_err(from_risk_error)?;
72
73 drop(data);
74
75 let bump = [header.bump];
76 let signer_seeds = market_signer_seeds(&header.authority, &bump);
77 transfer_checked(
78 CpiContext::new_with_signer(
79 ctx.accounts.token_program.key(),
80 TransferChecked {
81 from: ctx.accounts.vault.to_account_info(),
82 to: ctx.accounts.authority_token_account.to_account_info(),
83 authority: ctx.accounts.market.to_account_info(),
84 mint: ctx.accounts.mint.to_account_info(),
85 },
86 &[&signer_seeds],
87 ),
88 amount,
89 ctx.accounts.mint.decimals,
90 )?;
91
92 emit!(events::InsuranceWithdrawn {
93 authority: ctx.accounts.authority.key(),
94 amount,
95 });
96
97 Ok(())
98}