Clarkeni/oracle confidence (#568)
* Add oracle confidence and oracle type to update funding logs. * Return price and OracleState struct from oracle_price_and_state.
This commit is contained in:
parent
3600b6592c
commit
c0ea9970b6
|
@ -7881,6 +7881,78 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PerpUpdateFundingLogV2",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mangoGroup",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "marketIndex",
|
||||
"type": "u16",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "longFunding",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "shortFunding",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "oracleSlot",
|
||||
"type": "u64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "oracleConfidence",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "oracleType",
|
||||
"type": {
|
||||
"defined": "OracleType"
|
||||
},
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "stablePrice",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "feesAccrued",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "feesSettled",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "openInterest",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "instantaneousFundingRate",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "UpdateIndexLog",
|
||||
"fields": [
|
||||
|
|
|
@ -30,13 +30,13 @@ pub fn perp_place_order(
|
|||
asks: ctx.accounts.asks.load_mut()?,
|
||||
};
|
||||
|
||||
let oracle_slot;
|
||||
(oracle_price, oracle_slot) = perp_market.oracle_price_and_slot(
|
||||
let oracle_state;
|
||||
(oracle_price, oracle_state) = perp_market.oracle_price_and_state(
|
||||
&AccountInfoRef::borrow(ctx.accounts.oracle.as_ref())?,
|
||||
None, // staleness checked in health
|
||||
)?;
|
||||
|
||||
perp_market.update_funding_and_stable_price(&book, oracle_price, oracle_slot, now_ts)?;
|
||||
perp_market.update_funding_and_stable_price(&book, oracle_price, oracle_state, now_ts)?;
|
||||
}
|
||||
|
||||
let mut account = ctx.accounts.account.load_full_mut()?;
|
||||
|
|
|
@ -14,12 +14,12 @@ pub fn perp_update_funding(ctx: Context<PerpUpdateFunding>) -> Result<()> {
|
|||
};
|
||||
|
||||
let now_slot = Clock::get()?.slot;
|
||||
let (oracle_price, oracle_slot) = perp_market.oracle_price_and_slot(
|
||||
let (oracle_price, oracle_state) = perp_market.oracle_price_and_state(
|
||||
&AccountInfoRef::borrow(ctx.accounts.oracle.as_ref())?,
|
||||
Some(now_slot),
|
||||
)?;
|
||||
|
||||
perp_market.update_funding_and_stable_price(&book, oracle_price, oracle_slot, now_ts)?;
|
||||
perp_market.update_funding_and_stable_price(&book, oracle_price, oracle_state, now_ts)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::{
|
||||
accounts_ix::FlashLoanType,
|
||||
state::{PerpMarket, PerpPosition},
|
||||
state::{OracleType, PerpMarket, PerpPosition},
|
||||
};
|
||||
use anchor_lang::prelude::*;
|
||||
use borsh::BorshSerialize;
|
||||
|
@ -152,6 +152,23 @@ pub struct PerpUpdateFundingLog {
|
|||
pub instantaneous_funding_rate: i128,
|
||||
}
|
||||
|
||||
#[event]
|
||||
pub struct PerpUpdateFundingLogV2 {
|
||||
pub mango_group: Pubkey,
|
||||
pub market_index: u16,
|
||||
pub long_funding: i128,
|
||||
pub short_funding: i128,
|
||||
pub price: i128,
|
||||
pub oracle_slot: u64,
|
||||
pub oracle_confidence: i128,
|
||||
pub oracle_type: OracleType,
|
||||
pub stable_price: i128,
|
||||
pub fees_accrued: i128,
|
||||
pub fees_settled: i128,
|
||||
pub open_interest: i64,
|
||||
pub instantaneous_funding_rate: i128,
|
||||
}
|
||||
|
||||
#[event]
|
||||
pub struct UpdateIndexLog {
|
||||
pub mango_group: Pubkey,
|
||||
|
|
|
@ -789,7 +789,7 @@ impl Bank {
|
|||
staleness_slot: Option<u64>,
|
||||
) -> Result<I80F48> {
|
||||
require_keys_eq!(self.oracle, *oracle_acc.key());
|
||||
let (price, _) = oracle::oracle_price_and_slot(
|
||||
let (price, _) = oracle::oracle_price_and_state(
|
||||
oracle_acc,
|
||||
&self.oracle_config,
|
||||
self.mint_decimals,
|
||||
|
|
|
@ -83,7 +83,7 @@ impl OracleConfigParams {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[derive(PartialEq, AnchorSerialize, AnchorDeserialize)]
|
||||
pub enum OracleType {
|
||||
Pyth,
|
||||
Stub,
|
||||
|
@ -91,6 +91,12 @@ pub enum OracleType {
|
|||
SwitchboardV2,
|
||||
}
|
||||
|
||||
pub struct OracleState {
|
||||
pub last_update_slot: u64,
|
||||
pub confidence: I80F48,
|
||||
pub oracle_type: OracleType,
|
||||
}
|
||||
|
||||
#[account(zero_copy(safe_bytemuck_derives))]
|
||||
pub struct StubOracle {
|
||||
// ABI: Clients rely on this being at offset 8
|
||||
|
@ -135,18 +141,25 @@ 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_and_slot(
|
||||
pub fn oracle_price_and_state(
|
||||
acc_info: &impl KeyedAccountReader,
|
||||
config: &OracleConfig,
|
||||
base_decimals: u8,
|
||||
staleness_slot: Option<u64>,
|
||||
) -> Result<(I80F48, u64)> {
|
||||
) -> Result<(I80F48, OracleState)> {
|
||||
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, 0),
|
||||
OracleType::Stub => (
|
||||
acc_info.load::<StubOracle>()?.price,
|
||||
OracleState {
|
||||
last_update_slot: 0,
|
||||
confidence: I80F48::ZERO,
|
||||
oracle_type: OracleType::Stub,
|
||||
},
|
||||
),
|
||||
OracleType::Pyth => {
|
||||
let price_account = pyth_sdk_solana::state::load_price_account(data).unwrap();
|
||||
let price_data = price_account.to_price();
|
||||
|
@ -187,7 +200,14 @@ pub fn oracle_price_and_slot(
|
|||
|
||||
let decimals = (price_account.expo as i8) + QUOTE_DECIMALS - (base_decimals as i8);
|
||||
let decimal_adj = power_of_ten(decimals);
|
||||
(price * decimal_adj, last_slot)
|
||||
(
|
||||
price * decimal_adj,
|
||||
OracleState {
|
||||
last_update_slot: last_slot,
|
||||
confidence: I80F48::from_num(price_data.conf),
|
||||
oracle_type: OracleType::Pyth,
|
||||
},
|
||||
)
|
||||
}
|
||||
OracleType::SwitchboardV2 => {
|
||||
fn from_foreign_error(e: impl std::fmt::Display) -> Error {
|
||||
|
@ -233,7 +253,14 @@ pub fn oracle_price_and_slot(
|
|||
|
||||
let decimals = QUOTE_DECIMALS - (base_decimals as i8);
|
||||
let decimal_adj = power_of_ten(decimals);
|
||||
(price * decimal_adj, round_open_slot)
|
||||
(
|
||||
price * decimal_adj,
|
||||
OracleState {
|
||||
last_update_slot: round_open_slot,
|
||||
confidence: I80F48::from_num(std_deviation_decimal),
|
||||
oracle_type: OracleType::SwitchboardV2,
|
||||
},
|
||||
)
|
||||
}
|
||||
OracleType::SwitchboardV1 => {
|
||||
let result = FastRoundResultAccountData::deserialize(data).unwrap();
|
||||
|
@ -269,7 +296,14 @@ pub fn oracle_price_and_slot(
|
|||
|
||||
let decimals = QUOTE_DECIMALS - (base_decimals as i8);
|
||||
let decimal_adj = power_of_ten(decimals);
|
||||
(price * decimal_adj, round_open_slot)
|
||||
(
|
||||
price * decimal_adj,
|
||||
OracleState {
|
||||
last_update_slot: round_open_slot,
|
||||
confidence: max_response - min_response,
|
||||
oracle_type: OracleType::SwitchboardV1,
|
||||
},
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -7,11 +7,11 @@ use static_assertions::const_assert_eq;
|
|||
|
||||
use crate::accounts_zerocopy::KeyedAccountReader;
|
||||
use crate::error::MangoError;
|
||||
use crate::logs::PerpUpdateFundingLog;
|
||||
use crate::logs::PerpUpdateFundingLogV2;
|
||||
use crate::state::orderbook::Side;
|
||||
use crate::state::{oracle, TokenIndex};
|
||||
|
||||
use super::{orderbook, OracleConfig, Orderbook, StablePriceModel, DAY_I80F48};
|
||||
use super::{orderbook, OracleConfig, OracleState, Orderbook, StablePriceModel, DAY_I80F48};
|
||||
|
||||
pub type PerpMarketIndex = u16;
|
||||
|
||||
|
@ -246,7 +246,7 @@ impl PerpMarket {
|
|||
staleness_slot: Option<u64>,
|
||||
) -> Result<I80F48> {
|
||||
require_keys_eq!(self.oracle, *oracle_acc.key());
|
||||
let (price, _) = oracle::oracle_price_and_slot(
|
||||
let (price, _) = oracle::oracle_price_and_state(
|
||||
oracle_acc,
|
||||
&self.oracle_config,
|
||||
self.base_decimals,
|
||||
|
@ -256,13 +256,13 @@ impl PerpMarket {
|
|||
Ok(price)
|
||||
}
|
||||
|
||||
pub fn oracle_price_and_slot(
|
||||
pub fn oracle_price_and_state(
|
||||
&self,
|
||||
oracle_acc: &impl KeyedAccountReader,
|
||||
staleness_slot: Option<u64>,
|
||||
) -> Result<(I80F48, u64)> {
|
||||
) -> Result<(I80F48, OracleState)> {
|
||||
require_keys_eq!(self.oracle, *oracle_acc.key());
|
||||
oracle::oracle_price_and_slot(
|
||||
oracle::oracle_price_and_state(
|
||||
oracle_acc,
|
||||
&self.oracle_config,
|
||||
self.base_decimals,
|
||||
|
@ -279,7 +279,7 @@ impl PerpMarket {
|
|||
&mut self,
|
||||
book: &Orderbook,
|
||||
oracle_price: I80F48,
|
||||
oracle_slot: u64,
|
||||
oracle_state: OracleState,
|
||||
now_ts: u64,
|
||||
) -> Result<()> {
|
||||
if now_ts <= self.funding_last_updated {
|
||||
|
@ -331,13 +331,15 @@ impl PerpMarket {
|
|||
self.stable_price_model
|
||||
.update(now_ts, oracle_price.to_num());
|
||||
|
||||
emit!(PerpUpdateFundingLog {
|
||||
emit!(PerpUpdateFundingLogV2 {
|
||||
mango_group: self.group,
|
||||
market_index: self.perp_market_index,
|
||||
long_funding: self.long_funding.to_bits(),
|
||||
short_funding: self.short_funding.to_bits(),
|
||||
price: oracle_price.to_bits(),
|
||||
oracle_slot: oracle_slot,
|
||||
oracle_slot: oracle_state.last_update_slot,
|
||||
oracle_confidence: oracle_state.confidence.to_bits(),
|
||||
oracle_type: oracle_state.oracle_type,
|
||||
stable_price: self.stable_price().to_bits(),
|
||||
fees_accrued: self.fees_accrued.to_bits(),
|
||||
fees_settled: self.fees_settled.to_bits(),
|
||||
|
|
|
@ -7881,6 +7881,78 @@ export type MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PerpUpdateFundingLogV2",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mangoGroup",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "marketIndex",
|
||||
"type": "u16",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "longFunding",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "shortFunding",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "oracleSlot",
|
||||
"type": "u64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "oracleConfidence",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "oracleType",
|
||||
"type": {
|
||||
"defined": "OracleType"
|
||||
},
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "stablePrice",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "feesAccrued",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "feesSettled",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "openInterest",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "instantaneousFundingRate",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "UpdateIndexLog",
|
||||
"fields": [
|
||||
|
@ -16896,6 +16968,78 @@ export const IDL: MangoV4 = {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PerpUpdateFundingLogV2",
|
||||
"fields": [
|
||||
{
|
||||
"name": "mangoGroup",
|
||||
"type": "publicKey",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "marketIndex",
|
||||
"type": "u16",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "longFunding",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "shortFunding",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "price",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "oracleSlot",
|
||||
"type": "u64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "oracleConfidence",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "oracleType",
|
||||
"type": {
|
||||
"defined": "OracleType"
|
||||
},
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "stablePrice",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "feesAccrued",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "feesSettled",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "openInterest",
|
||||
"type": "i64",
|
||||
"index": false
|
||||
},
|
||||
{
|
||||
"name": "instantaneousFundingRate",
|
||||
"type": "i128",
|
||||
"index": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "UpdateIndexLog",
|
||||
"fields": [
|
||||
|
|
Loading…
Reference in New Issue