Files
agnostic_orderbook
ahash
aho_corasick
arrayref
arrayvec
atty
base64
bincode
blake3
block_buffer
block_padding
borsh
borsh_derive
borsh_derive_internal
borsh_schema_derive_internal
bs58
bv
bytemuck
byteorder
cfg_if
constant_time_eq
cpufeatures
crunchy
crypto_mac
curve25519_dalek
derivative
dex_v3
digest
either
enumflags2
enumflags2_derive
env_logger
generic_array
getrandom
hashbrown
hex
hmac
hmac_drbg
humantime
itertools
keccak
lazy_static
libc
libm
libsecp256k1
libsecp256k1_core
log
memchr
memmap2
num_derive
num_enum
num_enum_derive
num_traits
opaque_debug
ppv_lite86
proc_macro2
quote
rand
rand_chacha
rand_core
rand_pcg
regex
regex_syntax
rustversion
serde
serde_bytes
serde_derive
sha2
sha3
solana_frozen_abi
solana_frozen_abi_macro
solana_logger
solana_program
solana_sdk_macro
spin
spl_token
subtle
syn
synstructure
termcolor
thiserror
thiserror_impl
typenum
unicode_xid
zeroize
zeroize_derive
  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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint::ProgramResult,
    msg,
    program_error::ProgramError,
    pubkey::Pubkey,
};

use crate::{
    error::AoError,
    orderbook::OrderBookState,
    state::{
        EventQueue, EventQueueHeader, MarketState, SelfTradeBehavior, Side, EVENT_QUEUE_HEADER_LEN,
    },
    utils::{check_account_key, check_account_owner, check_signer},
    CRANKER_REWARD,
};

#[derive(BorshDeserialize, BorshSerialize, Clone)]
/**
The required arguments for a new_order instruction.
*/
pub struct Params {
    /// The maximum quantity of base to be traded.
    pub max_base_qty: u64,
    /// The maximum quantity of quote to be traded.
    pub max_quote_qty: u64,
    /// The limit price of the order. This value is understood as a 32-bit fixed point number.
    pub limit_price: u64,
    /// The order's side.
    pub side: Side,
    /// The maximum number of orders to match against before performing a partial fill.
    ///
    /// It is then possible for a caller program to detect a partial fill by reading the [`OrderSummary`][`crate::orderbook::OrderSummary`]
    /// in the event queue register.
    pub match_limit: u64,
    /// The callback information is used to attach metadata to an order. This callback information will be transmitted back through the event queue.
    ///
    /// The size of this vector should not exceed the current market's [`callback_info_len`][`MarketState::callback_info_len`].
    pub callback_info: Vec<u8>,
    /// The order will not be matched against the orderbook and will be direcly written into it.
    ///
    /// The operation will fail if the order's limit_price crosses the spread.
    pub post_only: bool,
    /// The order will be matched against the orderbook, but what remains will not be written as a new order into the orderbook.
    pub post_allowed: bool,
    /// Describes what would happen if this order was matched against an order with an equal `callback_info` field.
    pub self_trade_behavior: SelfTradeBehavior,
}

struct Accounts<'a, 'b: 'a> {
    market: &'a AccountInfo<'b>,
    event_queue: &'a AccountInfo<'b>,
    bids: &'a AccountInfo<'b>,
    asks: &'a AccountInfo<'b>,
    authority: &'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)?,
            event_queue: next_account_info(accounts_iter)?,
            bids: next_account_info(accounts_iter)?,
            asks: next_account_info(accounts_iter)?,
            authority: next_account_info(accounts_iter)?,
        };
        check_account_owner(a.market, program_id).unwrap();
        check_account_owner(a.event_queue, program_id).unwrap();
        check_account_owner(a.bids, program_id).unwrap();
        check_account_owner(a.asks, program_id).unwrap();
        check_signer(a.authority).unwrap();
        Ok(a)
    }
}

pub(crate) fn process(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    params: Params,
) -> ProgramResult {
    let accounts = Accounts::parse(program_id, accounts)?;
    let mut market_state = {
        let mut market_data: &[u8] = &accounts.market.data.borrow();
        MarketState::deserialize(&mut market_data)
            .unwrap()
            .check()?
    };

    check_account_key(accounts.event_queue, &market_state.event_queue)
        .map_err(|_| AoError::WrongEventQueueAccount)?;
    check_account_key(accounts.bids, &market_state.bids).map_err(|_| AoError::WrongBidsAccount)?;
    check_account_key(accounts.asks, &market_state.asks).map_err(|_| AoError::WrongAsksAccount)?;
    check_account_key(accounts.authority, &market_state.caller_authority)
        .map_err(|_| AoError::WrongCallerAuthority)?;

    let callback_info_len = market_state.callback_info_len as usize;

    let mut order_book = OrderBookState::new_safe(
        accounts.bids,
        accounts.asks,
        market_state.callback_info_len as usize,
        market_state.callback_id_len as usize,
    )?;

    if params.callback_info.len() != callback_info_len {
        msg!("Invalid callback information");
        return Err(ProgramError::InvalidArgument);
    }

    let header = {
        let mut event_queue_data: &[u8] =
            &accounts.event_queue.data.borrow()[0..EVENT_QUEUE_HEADER_LEN];
        EventQueueHeader::deserialize(&mut event_queue_data)
            .unwrap()
            .check()?
    };
    let mut event_queue = EventQueue::new_safe(header, &accounts.event_queue, callback_info_len)?;

    let order_summary = order_book.new_order(
        params,
        &mut &mut event_queue,
        market_state.min_base_order_size,
    )?;
    msg!("Order summary : {:?}", order_summary);
    event_queue.write_to_register(order_summary);

    let mut event_queue_header_data: &mut [u8] = &mut accounts.event_queue.data.borrow_mut();
    event_queue
        .header
        .serialize(&mut event_queue_header_data)
        .unwrap();
    order_book.commit_changes();

    //Verify that fees were transfered. Fees are expected to be transfered by the caller program in order
    // to reduce the CPI call stack depth.
    if accounts.market.lamports() - market_state.initial_lamports
        < market_state.fee_budget + CRANKER_REWARD
    {
        msg!("Fees were not correctly payed during caller runtime.");
        return Err(AoError::FeeNotPayed.into());
    }
    market_state.fee_budget = accounts.market.lamports() - market_state.initial_lamports;
    let mut market_state_data: &mut [u8] = &mut accounts.market.data.borrow_mut();
    market_state.serialize(&mut market_state_data).unwrap();

    Ok(())
}