Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix paddings #98

Open
wants to merge 48 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e25d873
pause logic
zachanon Aug 1, 2022
8d7a46a
frame
zachanon Aug 2, 2022
17e1af2
resume logic, untested
zachanon Aug 2, 2022
96dc897
Merge pull request #2 from Bonfida/main
zachanon Aug 14, 2022
cbc2fb2
unchecked
zachanon Aug 14, 2022
ccda443
Merge pull request #3 from jet-lab/unchecked-slab
zachanon Aug 14, 2022
276abd8
Merge branch 'Bonfida:main' into main
zachanon Aug 16, 2022
3d184dd
Merge branch 'Bonfida:main' into main
zachanon Aug 23, 2022
952a9a8
Merge branch 'main' of github.com:jet-lab/agnostic-orderbook into pau…
zachanon Aug 23, 2022
9c97363
pub use
zachanon Aug 23, 2022
4ea13bb
better bool type handling
zachanon Aug 23, 2022
db55e5f
price in order summary
zachanon Aug 23, 2022
7069c91
Merge branch 'pause-matching' of github.com:jet-lab/agnostic-orderboo…
zachanon Aug 23, 2022
93b1a9b
Revert "price in order summary"
zachanon Aug 23, 2022
4d3412e
hopefully no more infinite loop
zachanon Aug 23, 2022
d1cac50
Functionality for orderbook match pausing
zachanon Aug 23, 2022
b419632
make push event public
zachanon Sep 8, 2022
ab71e06
Expose `push_back` method
zachanon Sep 8, 2022
82006bd
make public
zachanon Sep 8, 2022
04a4364
Expose the `push_back` method and related types #5
zachanon Sep 8, 2022
1405412
pub
zachanon Oct 19, 2022
bf0ea9e
Merge pull request #9 from jet-lab/make-orderbook-public
zachanon Oct 19, 2022
2fb8ce6
when matching is disabled, the order summary returns the posted amoun…
dnut Oct 20, 2022
15c4729
Merge pull request #10 from jet-lab/paused-order-summary-posted-amounts
zachanon Oct 21, 2022
bb0d2c2
pause logic
zachanon Aug 1, 2022
87957af
frame
zachanon Aug 2, 2022
9482752
resume logic, untested
zachanon Aug 2, 2022
0e477ec
price in order summary
zachanon Aug 23, 2022
8e9e68e
unchecked
zachanon Aug 14, 2022
da41193
pub use
zachanon Aug 23, 2022
7866d0f
better bool type handling
zachanon Aug 23, 2022
93e9c1f
Revert "price in order summary"
zachanon Aug 23, 2022
756ea2d
hopefully no more infinite loop
zachanon Aug 23, 2022
fc3ade6
make push event public
zachanon Sep 8, 2022
1efd26a
make public
zachanon Sep 8, 2022
f0127f6
pub
zachanon Oct 19, 2022
9d15bca
when matching is disabled, the order summary returns the posted amoun…
dnut Oct 20, 2022
82b6aa1
Merge branch 'bonfida-updates'
zachanon Nov 15, 2022
3d861c1
cancel event
zachanon Nov 15, 2022
d97b6e1
cannot return callback, made fields public
zachanon Nov 15, 2022
231c24e
Merge pull request #13 from jet-lab/order-cancel-event
zachanon Nov 15, 2022
9267b4a
Merge github.com:Bonfida/agnostic-orderbook into merge-latest
zachanon Feb 17, 2023
b7a7986
fill event uses price information
zachanon Feb 17, 2023
2cc3731
struct not aligned properly
Jun 18, 2024
053ef62
struct not aligned properly
Jun 18, 2024
916416f
version upgrade
Jun 20, 2024
7e7472b
version upgrade
Jun 20, 2024
9c7f43b
add anchor serialize and deserialize
Jun 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4,216 changes: 3,004 additions & 1,212 deletions program/Cargo.lock

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions program/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ utils = []
benchmarking = ["bonfida-utils/benchmarking"]

[dependencies]
solana-program = "1.8.0"
solana-program = "1.18.17"
bytemuck = {version = "1.7.2", features= ["derive"]}
num_enum = "0.5.4"
borsh = "0.9.1"
Expand All @@ -31,18 +31,17 @@ bonfida-utils = "0.3.1"

[dev-dependencies]
hexdump = "0.1.0"
solana-sdk = "1.8.0"
solana-sdk = "1.18.17"
rand = "0.8.4"
arrayref = "0.3.6"
solana-program-test = "1.8.0"
solana-program-test = "1.18.17"
tokio = {version="1.6", features = ["macros"]}
regex = "1.5.5"
gnuplot = "0.0.37"
lazy_static = "1.4.0"
serde = "1"
serde_json = "1"


anchor-lang = "0.30.1"

[lib]
crate-type = ["cdylib", "lib"]
Expand Down
62 changes: 62 additions & 0 deletions program/src/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use bonfida_utils::{BorshSize, InstructionsAccount};

pub use crate::processor::{
cancel_order, close_market, consume_events, create_market, mass_cancel_orders, new_order,
pause_matching, resume_matching,
};
#[derive(BorshDeserialize, BorshSerialize, FromPrimitive)]
/// Describes all possible instructions and their required accounts
Expand Down Expand Up @@ -88,6 +89,28 @@ pub enum AgnosticOrderbookInstruction {
/// | 3 | ✅ | ❌ | The asks account |
/// | 4 | ❌ | ✅ | The caller authority |
MassCancelOrders,
/// Pause the matching engine.
///
/// Required accounts
///
/// | index | writable | signer | description |
/// |-------|----------|----------|-----------------------------|
/// | 0 | ✅ | ❌ | The market account |
PauseMatching,
/// Resume matching on the order book
///
/// The instruction will proceed to match all crossing orders currently extant on the book
///
/// Required accounts
///
///
/// | index | writable | signer | description |
/// |-------|----------|--------|-------------------------|
/// | 0 | ✅ | ❌ | The market account |
/// | 1 | ✅ | ❌ | The event queue account |
/// | 2 | ✅ | ❌ | The bids account |
/// | 3 | ✅ | ❌ | The asks account |
ResumeMatching,
}

/**
Expand Down Expand Up @@ -225,3 +248,42 @@ pub fn mass_cancel_orders(
});
i
}

/// Pause the matching engine.
pub fn pause_matching(
accounts: pause_matching::Accounts<Pubkey>,
register_account: Pubkey,
params: pause_matching::Params,
) -> Instruction {
let mut i = accounts.get_instruction(
crate::id(),
AgnosticOrderbookInstruction::PauseMatching as u8,
params,
);

i.accounts.push(AccountMeta {
pubkey: register_account,
is_signer: false,
is_writable: true,
});
i
}
/// Pause the matching engine.
pub fn resume_matching(
accounts: resume_matching::Accounts<Pubkey>,
register_account: Pubkey,
params: resume_matching::Params,
) -> Instruction {
let mut i = accounts.get_instruction(
crate::id(),
AgnosticOrderbookInstruction::ResumeMatching as u8,
params,
);

i.accounts.push(AccountMeta {
pubkey: register_account,
is_signer: false,
is_writable: true,
});
i
}
12 changes: 12 additions & 0 deletions program/src/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub mod consume_events;
pub mod create_market;
pub mod mass_cancel_orders;
pub mod new_order;
pub mod pause_matching;
pub mod resume_matching;

pub fn process_instruction<C: Pod + BorshDeserialize + CallbackInfo + PartialEq>(
program_id: &Pubkey,
Expand Down Expand Up @@ -71,6 +73,16 @@ where
.map_err(|_| ProgramError::InvalidInstructionData)?;
return mass_cancel_orders::process::<C>(program_id, accounts, params).map(Some);
}
AgnosticOrderbookInstruction::PauseMatching => {
msg!("Instruction: Pause Matching");
let accounts = pause_matching::Accounts::parse(accounts)?;
pause_matching::process::<C>(program_id, accounts, pause_matching::Params {})?;
}
AgnosticOrderbookInstruction::ResumeMatching => {
msg!("Instruction: Resume Matching");
let accounts = resume_matching::Accounts::parse(accounts)?;
resume_matching::process::<C>(program_id, accounts, resume_matching::Params {})?;
}
}
Ok(None)
}
3 changes: 2 additions & 1 deletion program/src/processor/cancel_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ where

let mut order_book = OrderBookState::<C>::new_safe(&mut bids_guard, &mut asks_guard)?;

let slab = order_book.get_tree(get_side_from_order_id(params.order_id));
let side = get_side_from_order_id(params.order_id);
let slab = order_book.get_tree(side);
let (leaf_node, _) = slab
.remove_by_key(params.order_id)
.ok_or(AoError::OrderNotFound)?;
Expand Down
10 changes: 5 additions & 5 deletions program/src/processor/create_market.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ pub fn process<'a, 'b: 'a, C: Pod>(
MarketState::check_buffer_size(&market_data)?;
let market_state = MarketState::from_buffer(&mut market_data, AccountTag::Uninitialized)?;

*market_state = MarketState {
event_queue: *accounts.event_queue.key,
bids: *accounts.bids.key,
asks: *accounts.asks.key,
*market_state = MarketState::init_new(
accounts.event_queue.key,
accounts.bids.key,
accounts.asks.key,
min_base_order_size,
tick_size,
};
);

let mut event_queue_data = accounts.event_queue.data.borrow_mut();

Expand Down
10 changes: 8 additions & 2 deletions program/src/processor/new_order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,14 @@ where
let mut event_queue_guard = accounts.event_queue.data.borrow_mut();
let mut event_queue = EventQueue::from_buffer(&mut event_queue_guard, AccountTag::EventQueue)?;

let order_summary =
order_book.new_order(params, &mut event_queue, market_state.min_base_order_size)?;
let order_summary = match market_state.pause_matching == 0 {
true => order_book.new_order(params, &mut event_queue, market_state.min_base_order_size)?,
false => order_book.insert_without_matching(
params,
&mut event_queue,
market_state.min_base_order_size,
)?,
};
msg!("Order summary : {:?}", order_summary);

Ok(order_summary)
Expand Down
67 changes: 67 additions & 0 deletions program/src/processor/pause_matching.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! Close an existing market.
use crate::{
error::AoError,
state::{market_state::MarketState, orderbook::CallbackInfo, AccountTag},
utils::check_account_owner,
};
use bonfida_utils::{BorshSize, InstructionsAccount};
use borsh::{BorshDeserialize, BorshSerialize};
use bytemuck::Pod;
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint::ProgramResult,
program_error::ProgramError,
pubkey::Pubkey,
};

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

/// The required accounts for a close_market instruction.
#[derive(InstructionsAccount)]
pub struct Accounts<'a, T> {
#[allow(missing_docs)]
#[cons(writable)]
pub market: &'a T,
}

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

let a = Self {
market: next_account_info(accounts_iter)?,
};
Ok(a)
}

pub(crate) fn perform_checks(&self, program_id: &Pubkey) -> Result<(), ProgramError> {
check_account_owner(
self.market,
&program_id.to_bytes(),
AoError::WrongMarketOwner,
)?;
Ok(())
}
}
/// Apply the close_market instruction to the provided accounts
pub fn process<'a, 'b: 'a, C: CallbackInfo + PartialEq + Pod>(
program_id: &Pubkey,
accounts: Accounts<'a, AccountInfo<'b>>,
_params: Params,
) -> ProgramResult
where
<C as CallbackInfo>::CallbackId: PartialEq,
{
accounts.perform_checks(program_id)?;
let mut market_data = accounts.market.data.borrow_mut();
let market_state = MarketState::from_buffer(&mut market_data, AccountTag::Market)?;

// bytemuck does not like boolean values
market_state.pause_matching = true as u8;

Ok(())
}
128 changes: 128 additions & 0 deletions program/src/processor/resume_matching.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//! Execute a new order on the orderbook

use bonfida_utils::{BorshSize, InstructionsAccount};
use borsh::{BorshDeserialize, BorshSerialize};
use bytemuck::Pod;
use solana_program::{
account_info::{next_account_info, AccountInfo},
entrypoint::ProgramResult,
msg,
program_error::ProgramError,
pubkey::Pubkey,
};

use crate::{
error::AoError,
state::{
event_queue::EventQueue,
market_state::MarketState,
orderbook::{CallbackInfo, OrderBookState},
AccountTag,
},
utils::{check_account_key, check_account_owner},
};

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

/// The required accounts for a new_order instruction.
#[derive(InstructionsAccount)]
pub struct Accounts<'a, T> {
#[allow(missing_docs)]
pub market: &'a T,
#[allow(missing_docs)]
#[cons(writable)]
pub event_queue: &'a T,
#[allow(missing_docs)]
#[cons(writable)]
pub bids: &'a T,
#[allow(missing_docs)]
#[cons(writable)]
pub asks: &'a T,
}

impl<'a, 'b: 'a> Accounts<'a, AccountInfo<'b>> {
pub(crate) fn parse(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)?,
};
Ok(a)
}
pub(crate) fn perform_checks(&self, program_id: &Pubkey) -> Result<(), ProgramError> {
check_account_owner(
self.market,
&program_id.to_bytes(),
AoError::WrongMarketOwner,
)?;
check_account_owner(
self.event_queue,
&program_id.to_bytes(),
AoError::WrongEventQueueOwner,
)?;
check_account_owner(self.bids, &program_id.to_bytes(), AoError::WrongBidsOwner)?;
check_account_owner(self.asks, &program_id.to_bytes(), AoError::WrongAsksOwner)?;
Ok(())
}
}

/// Apply the new_order instruction to the provided accounts
pub fn process<'a, 'b: 'a, C: Pod + CallbackInfo + PartialEq>(
program_id: &Pubkey,
accounts: Accounts<'a, AccountInfo<'b>>,
_params: Params,
) -> ProgramResult
where
<C as CallbackInfo>::CallbackId: PartialEq,
{
accounts.perform_checks(program_id)?;
let mut market_data = accounts.market.data.borrow_mut();
let market_state = MarketState::from_buffer(&mut market_data, AccountTag::Market)?;

check_accounts(&accounts, market_state)?;

let mut bids_guard = accounts.bids.data.borrow_mut();
let mut asks_guard = accounts.asks.data.borrow_mut();

let mut order_book = OrderBookState::<C>::new_safe(&mut bids_guard, &mut asks_guard)?;

let mut event_queue_guard = accounts.event_queue.data.borrow_mut();
let mut event_queue =
EventQueue::<C>::from_buffer(&mut event_queue_guard, AccountTag::EventQueue)?;

match order_book.match_existing_orders(&mut event_queue, market_state.min_base_order_size) {
Ok(completed) => {
if completed {
msg!("All sitting orders have been filled. Regular mathcing behavior resumed.");
market_state.pause_matching = false as u8;
} else {
msg!("Unmatched orders remain. Please run this instruction again to clear them before resuming regular behavior.");
}

Ok(())
}
Err(e) => Err(e.into()),
}
}

fn check_accounts<'a, 'b: 'a>(
accounts: &Accounts<'a, AccountInfo<'b>>,
market_state: &MarketState,
) -> ProgramResult {
check_account_key(
accounts.event_queue,
&market_state.event_queue,
AoError::WrongEventQueueAccount,
)?;
check_account_key(accounts.bids, &market_state.bids, AoError::WrongBidsAccount)?;
check_account_key(accounts.asks, &market_state.asks, AoError::WrongAsksAccount)?;

Ok(())
}
Loading