Clarkeni/perp trade logging (#535)

* Emit the slot corresponding to the oracle price to PerpUpdateFundingLog.

* Emit a new FilledPerpOrderLog consisting of just the group, perp market and seq num. This will be used to correlate perp fills to the transactions they were matched (not consumed).
This commit is contained in:
Nicholas Clarke 2023-04-13 10:50:39 -07:00 committed by GitHub
parent c813940054
commit 37ae7549fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 49 additions and 13 deletions

View File

@ -30,12 +30,13 @@ pub fn perp_place_order(
asks: ctx.accounts.asks.load_mut()?,
};
oracle_price = perp_market.oracle_price(
let oracle_slot;
(oracle_price, oracle_slot) = perp_market.oracle_price_and_slot(
&AccountInfoRef::borrow(ctx.accounts.oracle.as_ref())?,
None, // staleness checked in health
)?;
perp_market.update_funding_and_stable_price(&book, oracle_price, now_ts)?;
perp_market.update_funding_and_stable_price(&book, oracle_price, oracle_slot, now_ts)?;
}
let mut account = ctx.accounts.account.load_full_mut()?;

View File

@ -14,12 +14,12 @@ pub fn perp_update_funding(ctx: Context<PerpUpdateFunding>) -> Result<()> {
};
let now_slot = Clock::get()?.slot;
let oracle_price = perp_market.oracle_price(
let (oracle_price, oracle_slot) = perp_market.oracle_price_and_slot(
&AccountInfoRef::borrow(ctx.accounts.oracle.as_ref())?,
Some(now_slot),
)?;
perp_market.update_funding_and_stable_price(&book, oracle_price, now_ts)?;
perp_market.update_funding_and_stable_price(&book, oracle_price, oracle_slot, now_ts)?;
Ok(())
}

View File

@ -144,6 +144,7 @@ pub struct PerpUpdateFundingLog {
pub long_funding: i128,
pub short_funding: i128,
pub price: i128,
pub oracle_slot: u64,
pub stable_price: i128,
pub fees_accrued: i128,
pub fees_settled: i128,
@ -371,3 +372,10 @@ pub struct AccountBuybackFeesWithMngoLog {
pub mngo_buyback_price: i128,
pub oracle_price: i128,
}
#[event]
pub struct FilledPerpOrderLog {
pub mango_group: Pubkey,
pub perp_market_index: u16,
pub seq_num: u64,
}

View File

@ -789,12 +789,14 @@ impl Bank {
staleness_slot: Option<u64>,
) -> Result<I80F48> {
require_keys_eq!(self.oracle, *oracle_acc.key());
oracle::oracle_price(
let (price, _) = oracle::oracle_price_and_slot(
oracle_acc,
&self.oracle_config,
self.mint_decimals,
staleness_slot,
)
)?;
Ok(price)
}
pub fn stable_price(&self) -> I80F48 {

View File

@ -135,18 +135,18 @@ pub fn determine_oracle_type(acc_info: &impl KeyedAccountReader) -> Result<Oracl
/// This currently assumes that quote decimals is 6, like for USDC.
///
/// Pass `staleness_slot` = None to skip the staleness check
pub fn oracle_price(
pub fn oracle_price_and_slot(
acc_info: &impl KeyedAccountReader,
config: &OracleConfig,
base_decimals: u8,
staleness_slot: Option<u64>,
) -> Result<I80F48> {
) -> Result<(I80F48, u64)> {
let data = &acc_info.data();
let oracle_type = determine_oracle_type(acc_info)?;
let staleness_slot = staleness_slot.unwrap_or(0);
Ok(match oracle_type {
OracleType::Stub => acc_info.load::<StubOracle>()?.price,
OracleType::Stub => (acc_info.load::<StubOracle>()?.price, 0),
OracleType::Pyth => {
let price_account = pyth_sdk_solana::state::load_price_account(data).unwrap();
let price_data = price_account.to_price();
@ -187,7 +187,7 @@ pub fn oracle_price(
let decimals = (price_account.expo as i8) + QUOTE_DECIMALS - (base_decimals as i8);
let decimal_adj = power_of_ten(decimals);
price * decimal_adj
(price * decimal_adj, last_slot)
}
OracleType::SwitchboardV2 => {
fn from_foreign_error(e: impl std::fmt::Display) -> Error {
@ -233,7 +233,7 @@ pub fn oracle_price(
let decimals = QUOTE_DECIMALS - (base_decimals as i8);
let decimal_adj = power_of_ten(decimals);
price * decimal_adj
(price * decimal_adj, round_open_slot)
}
OracleType::SwitchboardV1 => {
let result = FastRoundResultAccountData::deserialize(data).unwrap();
@ -269,7 +269,7 @@ pub fn oracle_price(
let decimals = QUOTE_DECIMALS - (base_decimals as i8);
let decimal_adj = power_of_ten(decimals);
price * decimal_adj
(price * decimal_adj, round_open_slot)
}
})
}

View File

@ -1,3 +1,4 @@
use crate::logs::FilledPerpOrderLog;
use crate::state::MangoAccountRefMut;
use crate::{
error::*,
@ -155,6 +156,12 @@ impl<'a> Orderbook<'a> {
);
event_queue.push_back(cast(fill)).unwrap();
limit -= 1;
emit!(FilledPerpOrderLog {
mango_group: market.group.key(),
perp_market_index: market.perp_market_index,
seq_num: event_queue.header.seq_num,
});
}
let total_quote_lots_taken = order.max_quote_lots - remaining_quote_lots;
let total_base_lots_taken = order.max_base_lots - remaining_base_lots;

View File

@ -241,7 +241,23 @@ impl PerpMarket {
staleness_slot: Option<u64>,
) -> Result<I80F48> {
require_keys_eq!(self.oracle, *oracle_acc.key());
oracle::oracle_price(
let (price, _) = oracle::oracle_price_and_slot(
oracle_acc,
&self.oracle_config,
self.base_decimals,
staleness_slot,
)?;
Ok(price)
}
pub fn oracle_price_and_slot(
&self,
oracle_acc: &impl KeyedAccountReader,
staleness_slot: Option<u64>,
) -> Result<(I80F48, u64)> {
require_keys_eq!(self.oracle, *oracle_acc.key());
oracle::oracle_price_and_slot(
oracle_acc,
&self.oracle_config,
self.base_decimals,
@ -258,6 +274,7 @@ impl PerpMarket {
&mut self,
book: &Orderbook,
oracle_price: I80F48,
oracle_slot: u64,
now_ts: u64,
) -> Result<()> {
if now_ts <= self.funding_last_updated {
@ -315,6 +332,7 @@ impl PerpMarket {
long_funding: self.long_funding.to_bits(),
short_funding: self.short_funding.to_bits(),
price: oracle_price.to_bits(),
oracle_slot: oracle_slot,
stable_price: self.stable_price().to_bits(),
fees_accrued: self.fees_accrued.to_bits(),
fees_settled: self.fees_settled.to_bits(),