Fix oracle price read by using decimals from pyth (#62)
* Fix oracle price read by using decimals from pyth Signed-off-by: microwavedcola1 <microwavedcola@gmail.com> * fix Signed-off-by: microwavedcola1 <microwavedcola@gmail.com>
This commit is contained in:
parent
2274d5cade
commit
a20d04b6ff
|
@ -71,8 +71,8 @@ pub fn liq_token_with_token(
|
|||
account_retriever.bank_mut_and_oracle(asset_token_index)?;
|
||||
let (mut liab_bank, liab_oracle) =
|
||||
account_retriever.bank_mut_and_oracle(liab_token_index)?;
|
||||
let asset_price = oracle_price(asset_oracle)?;
|
||||
let liab_price = oracle_price(liab_oracle)?;
|
||||
let asset_price = oracle_price(asset_oracle, asset_bank.mint_decimals)?;
|
||||
let liab_price = oracle_price(liab_oracle, liab_bank.mint_decimals)?;
|
||||
|
||||
let liqee_assets_native = liqee
|
||||
.tokens
|
||||
|
|
|
@ -2,6 +2,7 @@ use anchor_lang::prelude::*;
|
|||
use fixed::types::I80F48;
|
||||
|
||||
use crate::error::MangoError;
|
||||
|
||||
use crate::state::*;
|
||||
use crate::util::fill16_from_str;
|
||||
|
||||
|
@ -46,6 +47,7 @@ pub fn perp_create_market(
|
|||
perp_market_index: PerpMarketIndex,
|
||||
name: String,
|
||||
base_token_index_opt: Option<TokenIndex>,
|
||||
base_token_decimals: u8,
|
||||
quote_token_index: TokenIndex,
|
||||
quote_lot_size: i64,
|
||||
base_lot_size: i64,
|
||||
|
@ -79,17 +81,18 @@ pub fn perp_create_market(
|
|||
taker_fee: I80F48::from_num(taker_fee),
|
||||
min_funding: I80F48::from_num(min_funding),
|
||||
max_funding: I80F48::from_num(max_funding),
|
||||
impact_quantity,
|
||||
long_funding: I80F48::ZERO,
|
||||
short_funding: I80F48::ZERO,
|
||||
funding_last_updated: Clock::get()?.unix_timestamp,
|
||||
impact_quantity,
|
||||
open_interest: 0,
|
||||
seq_num: 0,
|
||||
fees_accrued: I80F48::ZERO,
|
||||
bump: *ctx.bumps.get("perp_market").ok_or(MangoError::SomeError)?,
|
||||
reserved: Default::default(),
|
||||
perp_market_index,
|
||||
// Why optional - Perp could be based purely on an oracle
|
||||
base_token_index: base_token_index_opt.ok_or(TokenIndex::MAX).unwrap(),
|
||||
base_token_decimals,
|
||||
perp_market_index,
|
||||
quote_token_index,
|
||||
};
|
||||
|
||||
|
|
|
@ -89,7 +89,10 @@ pub fn perp_place_order(
|
|||
|
||||
let mut event_queue = ctx.accounts.event_queue.load_mut()?;
|
||||
|
||||
let oracle_price = oracle_price(&ctx.accounts.oracle.to_account_info())?;
|
||||
let oracle_price = oracle_price(
|
||||
&ctx.accounts.oracle.to_account_info(),
|
||||
perp_market.base_token_decimals,
|
||||
)?;
|
||||
|
||||
let now_ts = Clock::get()?.unix_timestamp as u64;
|
||||
let time_in_force = if expiry_timestamp != 0 {
|
||||
|
|
|
@ -27,7 +27,10 @@ pub fn perp_update_funding(ctx: Context<PerpUpdateFunding>) -> Result<()> {
|
|||
let asks = &ctx.accounts.asks.to_account_info();
|
||||
let book = Book::load_mut(bids, asks, &perp_market)?;
|
||||
|
||||
let oracle_price = oracle_price(&ctx.accounts.oracle.to_account_info())?;
|
||||
let oracle_price = oracle_price(
|
||||
&ctx.accounts.oracle.to_account_info(),
|
||||
perp_market.base_token_decimals,
|
||||
)?;
|
||||
|
||||
perp_market.update_funding(&book, oracle_price, now_ts as u64)?;
|
||||
|
||||
|
|
|
@ -196,6 +196,7 @@ pub mod mango_v4 {
|
|||
perp_market_index: PerpMarketIndex,
|
||||
name: String,
|
||||
base_token_index_opt: Option<TokenIndex>,
|
||||
base_token_decimals: u8,
|
||||
quote_token_index: TokenIndex,
|
||||
quote_lot_size: i64,
|
||||
base_lot_size: i64,
|
||||
|
@ -215,6 +216,7 @@ pub mod mango_v4 {
|
|||
perp_market_index,
|
||||
name,
|
||||
base_token_index_opt,
|
||||
base_token_decimals,
|
||||
quote_token_index,
|
||||
quote_lot_size,
|
||||
base_lot_size,
|
||||
|
|
|
@ -410,7 +410,7 @@ fn compute_health_detail<'a, 'b: 'a>(
|
|||
for (i, position) in account.tokens.iter_active().enumerate() {
|
||||
let (bank, oracle_ai) =
|
||||
retriever.bank_and_oracle(&account.group, i, position.token_index)?;
|
||||
let oracle_price = oracle_price(oracle_ai)?;
|
||||
let oracle_price = oracle_price(oracle_ai, bank.mint_decimals)?;
|
||||
|
||||
// converts the token value to the basis token value for health computations
|
||||
// TODO: health basis token == USDC?
|
||||
|
|
|
@ -5,9 +5,12 @@ use anchor_lang::Discriminator;
|
|||
use fixed::types::I80F48;
|
||||
use static_assertions::const_assert_eq;
|
||||
|
||||
use crate::checked_math as cm;
|
||||
use crate::error::MangoError;
|
||||
use crate::util::LoadZeroCopy;
|
||||
|
||||
pub const QUOTE_DECIMALS: u32 = 6;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum OracleType {
|
||||
Stub,
|
||||
|
@ -35,7 +38,7 @@ pub fn determine_oracle_type(data: &[u8]) -> Result<OracleType> {
|
|||
Err(MangoError::UnknownOracleType.into())
|
||||
}
|
||||
|
||||
pub fn oracle_price(acc_info: &AccountInfo) -> Result<I80F48> {
|
||||
pub fn oracle_price(acc_info: &AccountInfo, base_token_decimals: u8) -> Result<I80F48> {
|
||||
let data = &acc_info.try_borrow_data()?;
|
||||
let oracle_type = determine_oracle_type(data)?;
|
||||
|
||||
|
@ -43,7 +46,14 @@ pub fn oracle_price(acc_info: &AccountInfo) -> Result<I80F48> {
|
|||
OracleType::Stub => acc_info.load::<StubOracle>()?.price,
|
||||
OracleType::Pyth => {
|
||||
let price_struct = pyth_sdk_solana::load_price(data).unwrap();
|
||||
I80F48::from_num(price_struct.price)
|
||||
let price = I80F48::from_num(price_struct.price);
|
||||
let decimals = (price_struct.expo as u32)
|
||||
.checked_add(QUOTE_DECIMALS)
|
||||
.unwrap()
|
||||
.checked_sub(base_token_decimals as u32)
|
||||
.unwrap();
|
||||
let decimal_adj = I80F48::from_num(10_u32.pow(decimals));
|
||||
cm!(price * decimal_adj)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -71,10 +71,12 @@ pub struct PerpMarket {
|
|||
|
||||
/// PDA bump
|
||||
pub bump: u8,
|
||||
pub reserved: [u8; 1],
|
||||
|
||||
pub base_token_decimals: u8,
|
||||
|
||||
/// Lookup indices
|
||||
pub perp_market_index: PerpMarketIndex,
|
||||
|
||||
pub base_token_index: TokenIndex,
|
||||
|
||||
/// Cannot be chosen freely, must be the health-reference token, same for all PerpMarkets
|
||||
|
|
|
@ -1343,6 +1343,7 @@ pub struct PerpCreateMarketInstruction<'keypair> {
|
|||
pub payer: &'keypair Keypair,
|
||||
pub perp_market_index: PerpMarketIndex,
|
||||
pub base_token_index: TokenIndex,
|
||||
pub base_token_decimals: u8,
|
||||
pub quote_token_index: TokenIndex,
|
||||
pub quote_lot_size: i64,
|
||||
pub base_lot_size: i64,
|
||||
|
@ -1380,6 +1381,7 @@ impl<'keypair> ClientInstruction for PerpCreateMarketInstruction<'keypair> {
|
|||
max_funding: 0.05,
|
||||
min_funding: 0.05,
|
||||
impact_quantity: 100,
|
||||
base_token_decimals: self.base_token_decimals,
|
||||
};
|
||||
|
||||
let perp_market = Pubkey::find_program_address(
|
||||
|
@ -1636,6 +1638,7 @@ pub struct PerpUpdateFundingInstruction {
|
|||
pub perp_market: Pubkey,
|
||||
pub bids: Pubkey,
|
||||
pub asks: Pubkey,
|
||||
pub bank: Pubkey,
|
||||
pub oracle: Pubkey,
|
||||
}
|
||||
#[async_trait::async_trait(?Send)]
|
||||
|
|
|
@ -267,6 +267,7 @@ async fn test_health_compute_perp() -> Result<(), TransportError> {
|
|||
payer,
|
||||
perp_market_index: perp_market_index as PerpMarketIndex,
|
||||
base_token_index: quote_token.index,
|
||||
base_token_decimals: quote_token.mint.decimals,
|
||||
quote_token_index: token.index,
|
||||
quote_lot_size: 10,
|
||||
base_lot_size: 100,
|
||||
|
|
|
@ -149,6 +149,7 @@ async fn test_perp() -> Result<(), TransportError> {
|
|||
payer,
|
||||
perp_market_index: 0,
|
||||
base_token_index: tokens[0].index,
|
||||
base_token_decimals: tokens[0].mint.decimals,
|
||||
quote_token_index: tokens[1].index,
|
||||
quote_lot_size: 10,
|
||||
base_lot_size: 100,
|
||||
|
|
|
@ -700,6 +700,7 @@ export class MangoClient {
|
|||
perpMarketIndex: number,
|
||||
name: string,
|
||||
baseTokenIndex: number,
|
||||
baseTokenDecimals: number,
|
||||
quoteTokenIndex: number,
|
||||
quoteLotSize: number,
|
||||
baseLotSize: number,
|
||||
|
@ -723,6 +724,7 @@ export class MangoClient {
|
|||
perpMarketIndex,
|
||||
name,
|
||||
baseTokenIndex,
|
||||
baseTokenDecimals,
|
||||
quoteTokenIndex,
|
||||
new BN(quoteLotSize),
|
||||
new BN(baseLotSize),
|
||||
|
|
|
@ -1212,6 +1212,12 @@ export type MangoV4 = {
|
|||
"option": "u16"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "baseTokenDecimalsOpt",
|
||||
"type": {
|
||||
"option": "u8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "quoteTokenIndex",
|
||||
"type": "u16"
|
||||
|
@ -2149,13 +2155,8 @@ export type MangoV4 = {
|
|||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
}
|
||||
"name": "baseTokenDecimals",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "perpMarketIndex",
|
||||
|
@ -4112,6 +4113,12 @@ export const IDL: MangoV4 = {
|
|||
"option": "u16"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "baseTokenDecimalsOpt",
|
||||
"type": {
|
||||
"option": "u8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "quoteTokenIndex",
|
||||
"type": "u16"
|
||||
|
@ -5049,13 +5056,8 @@ export const IDL: MangoV4 = {
|
|||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "reserved",
|
||||
"type": {
|
||||
"array": [
|
||||
"u8",
|
||||
1
|
||||
]
|
||||
}
|
||||
"name": "baseTokenDecimals",
|
||||
"type": "u8"
|
||||
},
|
||||
{
|
||||
"name": "perpMarketIndex",
|
||||
|
|
|
@ -204,6 +204,7 @@ async function main() {
|
|||
0,
|
||||
'BTC/USDC',
|
||||
0,
|
||||
6,
|
||||
1,
|
||||
10,
|
||||
100,
|
||||
|
|
Loading…
Reference in New Issue