FixedOrderAccountRetriever uses fallback oracles
This commit is contained in:
parent
c22db3be0c
commit
d4017e6038
|
@ -47,6 +47,7 @@ pub trait AccountRetriever {
|
||||||
/// 3. PerpMarket accounts, in the order of account.perps.iter_active_accounts()
|
/// 3. PerpMarket accounts, in the order of account.perps.iter_active_accounts()
|
||||||
/// 4. PerpMarket oracle accounts, in the order of the perp market accounts
|
/// 4. PerpMarket oracle accounts, in the order of the perp market accounts
|
||||||
/// 5. serum3 OpenOrders accounts, in the order of account.serum3.iter_active()
|
/// 5. serum3 OpenOrders accounts, in the order of account.serum3.iter_active()
|
||||||
|
/// 6. fallback oracle accounts, order and existence of accounts is not guaranteed
|
||||||
pub struct FixedOrderAccountRetriever<T: KeyedAccountReader> {
|
pub struct FixedOrderAccountRetriever<T: KeyedAccountReader> {
|
||||||
pub ais: Vec<T>,
|
pub ais: Vec<T>,
|
||||||
pub n_banks: usize,
|
pub n_banks: usize,
|
||||||
|
@ -54,6 +55,7 @@ pub struct FixedOrderAccountRetriever<T: KeyedAccountReader> {
|
||||||
pub begin_perp: usize,
|
pub begin_perp: usize,
|
||||||
pub begin_serum3: usize,
|
pub begin_serum3: usize,
|
||||||
pub staleness_slot: Option<u64>,
|
pub staleness_slot: Option<u64>,
|
||||||
|
pub fallback_oracle_ais: Vec<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_fixed_order_account_retriever<'a, 'info>(
|
pub fn new_fixed_order_account_retriever<'a, 'info>(
|
||||||
|
@ -66,19 +68,22 @@ pub fn new_fixed_order_account_retriever<'a, 'info>(
|
||||||
let expected_ais = active_token_len * 2 // banks + oracles
|
let expected_ais = active_token_len * 2 // banks + oracles
|
||||||
+ active_perp_len * 2 // PerpMarkets + Oracles
|
+ active_perp_len * 2 // PerpMarkets + Oracles
|
||||||
+ active_serum3_len; // open_orders
|
+ active_serum3_len; // open_orders
|
||||||
require_msg_typed!(ais.len() == expected_ais, MangoError::InvalidHealthAccountCount,
|
require_msg_typed!(ais.len() >= expected_ais, MangoError::InvalidHealthAccountCount,
|
||||||
"received {} accounts but expected {} ({} banks, {} bank oracles, {} perp markets, {} perp oracles, {} serum3 oos)",
|
"received {} accounts but expected {} ({} banks, {} bank oracles, {} perp markets, {} perp oracles, {} serum3 oos)",
|
||||||
ais.len(), expected_ais,
|
ais.len(), expected_ais,
|
||||||
active_token_len, active_token_len, active_perp_len, active_perp_len, active_serum3_len
|
active_token_len, active_token_len, active_perp_len, active_perp_len, active_serum3_len
|
||||||
);
|
);
|
||||||
|
let fixed_ais = AccountInfoRef::borrow_slice(&ais[..expected_ais])?;
|
||||||
|
let fallback_oracle_ais = AccountInfoRef::borrow_slice(&ais[expected_ais..])?;
|
||||||
|
|
||||||
Ok(FixedOrderAccountRetriever {
|
Ok(FixedOrderAccountRetriever {
|
||||||
ais: AccountInfoRef::borrow_slice(ais)?,
|
ais: fixed_ais,
|
||||||
n_banks: active_token_len,
|
n_banks: active_token_len,
|
||||||
n_perps: active_perp_len,
|
n_perps: active_perp_len,
|
||||||
begin_perp: active_token_len * 2,
|
begin_perp: active_token_len * 2,
|
||||||
begin_serum3: active_token_len * 2 + active_perp_len * 2,
|
begin_serum3: active_token_len * 2 + active_perp_len * 2,
|
||||||
staleness_slot: Some(Clock::get()?.slot),
|
staleness_slot: Some(Clock::get()?.slot),
|
||||||
|
fallback_oracle_ais,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,11 +108,6 @@ impl<T: KeyedAccountReader> FixedOrderAccountRetriever<T> {
|
||||||
Ok(market)
|
Ok(market)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn oracle_price_bank(&self, account_index: usize, bank: &Bank) -> Result<I80F48> {
|
|
||||||
let oracle = &self.ais[account_index];
|
|
||||||
bank.oracle_price(oracle, self.staleness_slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn oracle_price_perp(&self, account_index: usize, perp_market: &PerpMarket) -> Result<I80F48> {
|
fn oracle_price_perp(&self, account_index: usize, perp_market: &PerpMarket) -> Result<I80F48> {
|
||||||
let oracle = &self.ais[account_index];
|
let oracle = &self.ais[account_index];
|
||||||
perp_market.oracle_price(oracle, self.staleness_slot)
|
perp_market.oracle_price(oracle, self.staleness_slot)
|
||||||
|
@ -134,7 +134,14 @@ impl<T: KeyedAccountReader> AccountRetriever for FixedOrderAccountRetriever<T> {
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let oracle_index = self.n_banks + active_token_position_index;
|
let oracle_index = self.n_banks + active_token_position_index;
|
||||||
let oracle_price = self.oracle_price_bank(oracle_index, bank).with_context(|| {
|
let oracle = &self.ais[oracle_index];
|
||||||
|
let fallback_opt = self
|
||||||
|
.fallback_oracle_ais
|
||||||
|
.iter()
|
||||||
|
.find(|ai| ai.key() == &bank.fallback_oracle);
|
||||||
|
let oracle_price_result =
|
||||||
|
bank.oracle_price_with_fallback(oracle, fallback_opt, self.staleness_slot);
|
||||||
|
let oracle_price = oracle_price_result.with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"getting oracle for bank with health account index {} and token index {}, passed account {}",
|
"getting oracle for bank with health account index {} and token index {}, passed account {}",
|
||||||
bank_account_index,
|
bank_account_index,
|
||||||
|
|
|
@ -3,10 +3,7 @@ use fixed::types::I80F48;
|
||||||
|
|
||||||
use crate::accounts_ix::*;
|
use crate::accounts_ix::*;
|
||||||
|
|
||||||
pub fn stub_oracle_create(
|
pub fn stub_oracle_create(ctx: Context<StubOracleCreate>, price: I80F48) -> Result<()> {
|
||||||
ctx: Context<StubOracleCreate>,
|
|
||||||
price: I80F48
|
|
||||||
) -> Result<()> {
|
|
||||||
let mut oracle = ctx.accounts.oracle.load_init()?;
|
let mut oracle = ctx.accounts.oracle.load_init()?;
|
||||||
oracle.group = ctx.accounts.group.key();
|
oracle.group = ctx.accounts.group.key();
|
||||||
oracle.mint = ctx.accounts.mint.key();
|
oracle.mint = ctx.accounts.mint.key();
|
||||||
|
|
|
@ -949,6 +949,14 @@ impl Bank {
|
||||||
staleness_slot: Option<u64>,
|
staleness_slot: Option<u64>,
|
||||||
) -> Result<I80F48> {
|
) -> Result<I80F48> {
|
||||||
require_keys_eq!(self.oracle, *oracle_acc.key());
|
require_keys_eq!(self.oracle, *oracle_acc.key());
|
||||||
|
self.oracle_price_inner(oracle_acc, staleness_slot)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn oracle_price_inner(
|
||||||
|
&self,
|
||||||
|
oracle_acc: &impl KeyedAccountReader,
|
||||||
|
staleness_slot: Option<u64>,
|
||||||
|
) -> Result<I80F48> {
|
||||||
let state = oracle::oracle_state_unchecked(oracle_acc, self.mint_decimals)?;
|
let state = oracle::oracle_state_unchecked(oracle_acc, self.mint_decimals)?;
|
||||||
state.check_confidence_and_maybe_staleness(
|
state.check_confidence_and_maybe_staleness(
|
||||||
&self.oracle,
|
&self.oracle,
|
||||||
|
@ -958,6 +966,23 @@ impl Bank {
|
||||||
Ok(state.price)
|
Ok(state.price)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Tries to return the primary oracle price, and if there is a confidence or staleness issue returns the fallback oracle price.
|
||||||
|
pub fn oracle_price_with_fallback(
|
||||||
|
&self,
|
||||||
|
oracle_acc: &impl KeyedAccountReader,
|
||||||
|
fallback_oracle_acc_opt: Option<&impl KeyedAccountReader>,
|
||||||
|
staleness_slot: Option<u64>,
|
||||||
|
) -> Result<I80F48> {
|
||||||
|
let primary_price = self.oracle_price(oracle_acc, staleness_slot);
|
||||||
|
if primary_price.is_ok() || fallback_oracle_acc_opt.is_none() {
|
||||||
|
primary_price
|
||||||
|
} else {
|
||||||
|
let fallback_oracle_acc = fallback_oracle_acc_opt.unwrap();
|
||||||
|
require_keys_eq!(self.fallback_oracle, *fallback_oracle_acc.key());
|
||||||
|
self.oracle_price_inner(fallback_oracle_acc, staleness_slot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn stable_price(&self) -> I80F48 {
|
pub fn stable_price(&self) -> I80F48 {
|
||||||
I80F48::from_num(self.stable_price_model.stable_price)
|
I80F48::from_num(self.stable_price_model.stable_price)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue