Skip to content

Commit

Permalink
Add orders_place_perp_order for local order validation (#3)
Browse files Browse the repository at this point in the history
* Add orders_place_perp_order local order sim

* fix OrderParams C abi
  • Loading branch information
jordy25519 authored Nov 21, 2024
1 parent d15dc2d commit bf33494
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 4 deletions.
93 changes: 91 additions & 2 deletions src/exports.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//!
//! Define FFI for subset of drift program
//!
use std::time::{SystemTime, UNIX_EPOCH};

use abi_stable::std_types::{
ROption,
RResult::{RErr, ROk},
Expand All @@ -10,14 +12,21 @@ use drift_program::{
state::{
oracle::{get_oracle_price as get_oracle_price_, OracleSource},
oracle_map::OracleMap,
order_params::PlaceOrderOptions,
perp_market::{ContractType, PerpMarket},
perp_market_map::PerpMarketMap,
spot_market::SpotMarket,
spot_market_map::SpotMarketMap,
state::State,
user::{Order, PerpPosition, SpotPosition, User},
},
};
use solana_sdk::{account::Account, account_info::IntoAccountInfo, clock::Slot, pubkey::Pubkey};
use solana_sdk::{
account::Account,
account_info::IntoAccountInfo,
clock::{Clock, Slot},
pubkey::Pubkey,
};

use crate::types::{
compat::{self},
Expand Down Expand Up @@ -114,6 +123,86 @@ pub extern "C" fn math_calculate_margin_requirement_and_total_collateral_and_lia
to_ffi_result(m)
}

#[no_mangle]
pub extern "C" fn orders_place_perp_order(
user: &User,
state: &State,
order_params: &crate::types::OrderParams,
accounts: &mut AccountsList,
) -> FfiResult<bool> {
let spot_accounts = accounts
.spot_markets
.iter_mut()
.map(IntoAccountInfo::into_account_info)
.collect::<Vec<_>>();
let spot_map =
SpotMarketMap::load(&Default::default(), &mut spot_accounts.iter().peekable()).unwrap();

let perp_accounts = accounts
.perp_markets
.iter_mut()
.map(IntoAccountInfo::into_account_info)
.collect::<Vec<_>>();
let perp_map =
PerpMarketMap::load(&Default::default(), &mut perp_accounts.iter().peekable()).unwrap();

let oracle_accounts = accounts
.oracles
.iter_mut()
.map(IntoAccountInfo::into_account_info)
.collect::<Vec<_>>();
let mut oracle_map = OracleMap::load(
&mut oracle_accounts.iter().peekable(),
accounts.latest_slot,
accounts.oracle_guard_rails,
)
.unwrap();

// has no epoch info but this is unrequired for orderplacement
let local_clock = Clock {
slot: accounts.latest_slot,
epoch_start_timestamp: 0,
epoch: 0,
leader_schedule_epoch: 0,
unix_timestamp: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() as i64,
};

let res = drift_program::controller::orders::place_perp_order(
state,
&mut user.clone(),
user.authority,
&perp_map,
&spot_map,
&mut oracle_map,
&local_clock,
drift_program::state::order_params::OrderParams {
order_type: order_params.order_type,
market_type: order_params.market_type,
direction: order_params.direction,
user_order_id: order_params.user_order_id,
base_asset_amount: order_params.base_asset_amount,
price: order_params.price,
market_index: order_params.market_index,
reduce_only: order_params.reduce_only,
post_only: order_params.post_only,
immediate_or_cancel: order_params.immediate_or_cancel,
max_ts: order_params.max_ts,
trigger_price: order_params.trigger_price,
trigger_condition: order_params.trigger_condition,
oracle_price_offset: order_params.oracle_price_offset,
auction_duration: order_params.auction_duration,
auction_start_price: order_params.auction_start_price,
auction_end_price: order_params.auction_end_price,
},
PlaceOrderOptions::default(),
);

to_ffi_result(res.map(|_| true))
}

#[no_mangle]
pub extern "C" fn order_is_limit_order(order: &Order) -> bool {
order.is_limit_order()
Expand Down Expand Up @@ -145,7 +234,7 @@ pub extern "C" fn perp_position_get_unrealized_pnl(
oracle_price: i64,
) -> FfiResult<compat::i128> {
to_ffi_result(position.get_unrealized_pnl(oracle_price).map(compat::i128))
}
}

#[no_mangle]
pub extern "C" fn perp_position_is_available(position: &PerpPosition) -> bool {
Expand Down
32 changes: 30 additions & 2 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
//! cross-boundary FFI types
use abi_stable::std_types::RResult;
use drift_program::{
controller::position::PositionDirection,
math::margin::MarginRequirementType,
state::{margin_calculation::MarginContext, state::OracleGuardRails},
state::{
margin_calculation::MarginContext,
order_params::PostOnlyParam,
state::OracleGuardRails,
user::{MarketType, OrderTriggerCondition, OrderType},
},
};
use solana_sdk::{
account::Account,
Expand Down Expand Up @@ -76,7 +82,6 @@ impl From<MarginContextMode> for MarginContext {
}
}


#[repr(C, align(16))]
#[derive(Copy, Clone, Debug, PartialEq, TypeLayout)]
pub struct MarginCalculation {
Expand All @@ -100,6 +105,29 @@ impl MarginCalculation {
}
}

/// Same as drift program `OrderParams` but with `C` layout
#[repr(C)]
#[derive(Debug)]
pub struct OrderParams {
pub order_type: OrderType,
pub market_type: MarketType,
pub direction: PositionDirection,
pub user_order_id: u8,
pub base_asset_amount: u64,
pub price: u64,
pub market_index: u16,
pub reduce_only: bool,
pub post_only: PostOnlyParam,
pub immediate_or_cancel: bool,
pub max_ts: Option<i64>,
pub trigger_price: Option<u64>,
pub trigger_condition: OrderTriggerCondition,
pub oracle_price_offset: Option<i32>, // price offset from oracle for order (~ +/- 2147 max)
pub auction_duration: Option<u8>, // specified in slots
pub auction_start_price: Option<i64>, // specified in price or oracle_price_offset
pub auction_end_price: Option<i64>, // specified in price or oracle_price_offset
}

#[repr(C)]
#[derive(Default, Clone, Copy, Debug)]
pub struct OraclePriceData {
Expand Down

0 comments on commit bf33494

Please sign in to comment.