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 borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint::ProgramResult,
    msg,
    program::invoke_signed,
    program_error::ProgramError,
    pubkey::Pubkey,
};

use crate::{
    error::DexError,
    state::DexState,
    utils::{check_account_key, check_signer},
};

#[derive(BorshDeserialize, BorshSerialize)]
/**
The required arguments for a create_market instruction.
*/
pub struct Params {}

struct Accounts<'a, 'b: 'a> {
    market: &'a AccountInfo<'b>,
    market_signer: &'a AccountInfo<'b>,
    market_admin: &'a AccountInfo<'b>,
    quote_vault: &'a AccountInfo<'b>,
    destination_token_account: &'a AccountInfo<'b>,
    spl_token_program: &'a AccountInfo<'b>,
}

impl<'a, 'b: 'a> Accounts<'a, 'b> {
    pub fn parse(
        _program_id: &Pubkey,
        accounts: &'a [AccountInfo<'b>],
    ) -> Result<Self, ProgramError> {
        let accounts_iter = &mut accounts.iter();

        let a = Self {
            market: next_account_info(accounts_iter)?,
            market_signer: next_account_info(accounts_iter)?,
            market_admin: next_account_info(accounts_iter)?,
            quote_vault: next_account_info(accounts_iter)?,
            destination_token_account: next_account_info(accounts_iter)?,
            spl_token_program: next_account_info(accounts_iter)?,
        };

        check_signer(a.market_admin).unwrap();
        check_account_key(a.spl_token_program, &spl_token::ID).unwrap();

        Ok(a)
    }
}

pub(crate) fn process(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult {
    let accounts = Accounts::parse(program_id, accounts)?;

    let mut market_state =
        DexState::deserialize(&mut (&accounts.market.data.borrow() as &[u8]))?.check()?;
    check_accounts(program_id, &market_state, &accounts)?;

    let transfer_instruction = spl_token::instruction::transfer(
        &spl_token::ID,
        accounts.quote_vault.key,
        accounts.destination_token_account.key,
        accounts.market_signer.key,
        &[],
        market_state.accumulated_fees,
    )?;

    if market_state.accumulated_fees == 0 {
        msg!("Therer are no fees to be extracted from the market");
        return Err(DexError::NoOp.into());
    }

    invoke_signed(
        &transfer_instruction,
        &[
            accounts.spl_token_program.clone(),
            accounts.quote_vault.clone(),
            accounts.destination_token_account.clone(),
            accounts.market_signer.clone(),
        ],
        &[&[
            &accounts.market.key.to_bytes(),
            &[market_state.signer_nonce],
        ]],
    )?;

    market_state.accumulated_fees = 0;
    let mut market_data: &mut [u8] = &mut accounts.market.data.borrow_mut();
    market_state.serialize(&mut market_data).unwrap();

    Ok(())
}

fn check_accounts(
    program_id: &Pubkey,
    market_state: &DexState,
    accounts: &Accounts,
) -> ProgramResult {
    let market_signer = Pubkey::create_program_address(
        &[
            &accounts.market.key.to_bytes(),
            &[market_state.signer_nonce],
        ],
        program_id,
    )?;
    check_account_key(accounts.market_signer, &market_signer).unwrap();
    check_account_key(accounts.quote_vault, &market_state.quote_vault).unwrap();
    check_account_key(accounts.market_admin, &market_state.admin).unwrap();
    Ok(())
}