Skip to content

Commit

Permalink
Time In Force (#23) (#25)
Browse files Browse the repository at this point in the history
Time-in-force (TIF) orders for Phoenix v1.

Changes:
- Uses the padding on the FIFORestingOrder to store and expiration slot
and an expiration time
- Modifies the OrderPacket struct to enable specification of expiration
- Injects logic into the matching engine to skip orders that are expired
  • Loading branch information
jarry-xiao authored and eugene-chen committed Mar 14, 2023
1 parent 72cd702 commit 21cd8e3
Show file tree
Hide file tree
Showing 17 changed files with 1,332 additions and 290 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "phoenix-v1"
version = "0.1.4"
version = "0.2.0"
edition = "2021"
resolver = "2"
repository = "https://github.com/Ellipsis-Labs/phoenix-v1"
Expand Down
16 changes: 13 additions & 3 deletions idl/generateClient.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { Solita } = require("@metaplex-foundation/solita");
const { spawn } = require("child_process");

const path = require("path");
const idlDir = __dirname;
Expand All @@ -8,7 +9,18 @@ const PROGRAM_NAME = "phoenix_v1";

async function main() {
generateTypeScriptSDK().then(() => {
conoole.log("done");
console.log("Running prettier on generated files...");
// Note: prettier is not a dependency of this package, so it must be installed
// TODO: Add a prettier config file for consistent style
spawn("prettier", ["--write", sdkDir], { stdio: "inherit" })
.on("error", (err) => {
console.error(
"Failed to lint client files. Try installing prettier (`npm install --save-dev --save-exact prettier`)"
);
})
.on("exit", () => {
console.log("Finished linting files.");
});
});
}

Expand All @@ -18,8 +30,6 @@ async function generateTypeScriptSDK() {
const idl = require(generatedIdlPath);
const gen = new Solita(idl, { formatCode: true });
await gen.renderAndWriteTo(sdkDir);
console.error("Success!");
process.exit(0);
}

main().catch((err) => {
Expand Down
106 changes: 105 additions & 1 deletion idl/phoenix_v1.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.1.4",
"version": "0.2.0",
"name": "phoenix_v1",
"instructions": [
{
Expand Down Expand Up @@ -1800,6 +1800,58 @@
]
}
},
{
"name": "TimeInForceEvent",
"type": {
"kind": "struct",
"fields": [
{
"name": "index",
"type": "u16"
},
{
"name": "orderSequenceNumber",
"type": "u64"
},
{
"name": "lastValidSlot",
"type": "u64"
},
{
"name": "lastValidUnixTimestampInSeconds",
"type": "u64"
}
]
}
},
{
"name": "ExpiredOrderEvent",
"type": {
"kind": "struct",
"fields": [
{
"name": "index",
"type": "u16"
},
{
"name": "makerId",
"type": "publicKey"
},
{
"name": "orderSequenceNumber",
"type": "u64"
},
{
"name": "priceInTicks",
"type": "u64"
},
{
"name": "baseLotsRemoved",
"type": "u64"
}
]
}
},
{
"name": "CancelUpToParams",
"type": {
Expand Down Expand Up @@ -1950,6 +2002,18 @@
{
"name": "sizeInBaseLots",
"type": "u64"
},
{
"name": "lastValidSlot",
"type": {
"option": "u64"
}
},
{
"name": "lastValidUnixTimestampInSeconds",
"type": {
"option": "u64"
}
}
]
}
Expand Down Expand Up @@ -2156,6 +2220,22 @@
"defined": "FeeEvent"
}
]
},
{
"name": "TimeInForce",
"fields": [
{
"defined": "TimeInForceEvent"
}
]
},
{
"name": "ExpiredOrder",
"fields": [
{
"defined": "ExpiredOrderEvent"
}
]
}
]
}
Expand Down Expand Up @@ -2236,6 +2316,18 @@
{
"name": "use_only_deposited_funds",
"type": "bool"
},
{
"name": "last_valid_slot",
"type": {
"option": "u64"
}
},
{
"name": "last_valid_unix_timestamp_in_seconds",
"type": {
"option": "u64"
}
}
]
},
Expand Down Expand Up @@ -2275,6 +2367,18 @@
{
"name": "use_only_deposited_funds",
"type": "bool"
},
{
"name": "last_valid_slot",
"type": {
"option": "u64"
}
},
{
"name": "last_valid_unix_timestamp_in_seconds",
"type": {
"option": "u64"
}
}
]
},
Expand Down
43 changes: 43 additions & 0 deletions src/program/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,23 @@ pub struct FeeEvent {
pub fees_collected_in_quote_lots: u64,
}

#[derive(Debug, Copy, Clone, BorshDeserialize, BorshSerialize)]
pub struct TimeInForceEvent {
pub index: u16,
pub order_sequence_number: u64,
pub last_valid_slot: u64,
pub last_valid_unix_timestamp_in_seconds: u64,
}

#[derive(Debug, Copy, Clone, BorshDeserialize, BorshSerialize)]
pub struct ExpiredOrderEvent {
pub index: u16,
pub maker_id: Pubkey,
pub order_sequence_number: u64,
pub price_in_ticks: u64,
pub base_lots_removed: u64,
}

#[derive(Debug, Copy, Clone, BorshDeserialize, BorshSerialize)]
pub enum PhoenixMarketEvent {
Uninitialized,
Expand All @@ -75,6 +92,8 @@ pub enum PhoenixMarketEvent {
Evict(EvictEvent),
FillSummary(FillSummaryEvent),
Fee(FeeEvent),
TimeInForce(TimeInForceEvent),
ExpiredOrder(ExpiredOrderEvent),
}

impl Default for PhoenixMarketEvent {
Expand All @@ -92,6 +111,8 @@ impl PhoenixMarketEvent {
Self::FillSummary(FillSummaryEvent { index, .. }) => *index = i,
Self::Evict(EvictEvent { index, .. }) => *index = i,
Self::Fee(FeeEvent { index, .. }) => *index = i,
Self::TimeInForce(TimeInForceEvent { index, .. }) => *index = i,
Self::ExpiredOrder(ExpiredOrderEvent { index, .. }) => *index = i,
_ => panic!("Cannot set index on uninitialized or header event"),
}
}
Expand Down Expand Up @@ -168,6 +189,28 @@ impl From<MarketEvent<Pubkey>> for PhoenixMarketEvent {
fees_collected_in_quote_lots: fees_collected_in_quote_lots.into(),
index: 0,
}),
MarketEvent::<Pubkey>::TimeInForce {
order_sequence_number,
last_valid_slot,
last_valid_unix_timestamp_in_seconds,
} => Self::TimeInForce(TimeInForceEvent {
order_sequence_number,
last_valid_slot,
last_valid_unix_timestamp_in_seconds,
index: 0,
}),
MarketEvent::<Pubkey>::ExpiredOrder {
maker_id,
order_sequence_number,
price_in_ticks,
base_lots_removed,
} => Self::ExpiredOrder(ExpiredOrderEvent {
maker_id,
order_sequence_number,
price_in_ticks: price_in_ticks.into(),
base_lots_removed: base_lots_removed.into(),
index: 0,
}),
}
}
}
20 changes: 17 additions & 3 deletions src/program/processor/cancel_multiple_orders.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::{
program::{
dispatch_market::load_with_dispatch_mut, loaders::CancelOrWithdrawContext as Cancel,
token_utils::try_withdraw, validation::checkers::phoenix_checkers::MarketAccountInfo,
MarketHeader, PhoenixMarketContext, PhoenixVaultContext,
assert_with_msg, dispatch_market::load_with_dispatch_mut,
loaders::CancelOrWithdrawContext as Cancel, token_utils::try_withdraw,
validation::checkers::phoenix_checkers::MarketAccountInfo, MarketHeader, PhoenixError,
PhoenixMarketContext, PhoenixVaultContext,
},
quantities::{Ticks, WrapperU64},
state::{
Expand Down Expand Up @@ -279,6 +280,19 @@ pub(crate) fn process_cancel_orders<'a, 'info>(
num_quote_lots_out * header.get_quote_lot_size(),
num_base_lots_out * header.get_base_lot_size(),
)?;
} else {
// This case is only reached if the user invoked CancelUpToWithFreeFunds
// In this case, there should be no funds to claim
assert_with_msg(
num_quote_lots_out == 0,
PhoenixError::CancelMultipleOrdersError,
"num_quote_lots_out must be 0",
)?;
assert_with_msg(
num_base_lots_out == 0,
PhoenixError::CancelMultipleOrdersError,
"num_base_lots_out must be 0",
)?;
}

Ok(())
Expand Down
Loading

0 comments on commit 21cd8e3

Please sign in to comment.