From da473b00b1fdc7e6c6a2886decdaecf7a3877a34 Mon Sep 17 00:00:00 2001 From: riordanp Date: Wed, 15 Mar 2023 13:44:51 +0000 Subject: [PATCH] Add oracleProvider to Bank and PerpMarket (#491) * Add oracleProvider to Bank and PerpMarket --- ts/client/src/accounts/bank.ts | 12 ++++++++++++ ts/client/src/accounts/group.ts | 21 ++++++++++++++++----- ts/client/src/accounts/oracle.ts | 6 ++++++ ts/client/src/accounts/perp.ts | 12 ++++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/ts/client/src/accounts/bank.ts b/ts/client/src/accounts/bank.ts index 120cbc541..9dd09ec8b 100644 --- a/ts/client/src/accounts/bank.ts +++ b/ts/client/src/accounts/bank.ts @@ -3,6 +3,7 @@ import { utf8 } from '@coral-xyz/anchor/dist/cjs/utils/bytes'; import { PublicKey } from '@solana/web3.js'; import { I80F48, I80F48Dto, ZERO_I80F48 } from '../numbers/I80F48'; import { As, toUiDecimals } from '../utils'; +import { OracleProvider } from './oracle'; export type TokenIndex = number & As<'token-index'>; @@ -58,6 +59,7 @@ export class Bank implements BankForHealth { public _price: I80F48 | undefined; public _uiPrice: number | undefined; public _oracleLastUpdatedSlot: number | undefined; + public _oracleProvider: OracleProvider | undefined; public collectedFeesNative: I80F48; public loanFeeRate: I80F48; public loanOriginationFeeRate: I80F48; @@ -235,6 +237,7 @@ export class Bank implements BankForHealth { this._price = undefined; this._uiPrice = undefined; this._oracleLastUpdatedSlot = undefined; + this._oracleProvider = undefined; } toString(): string { @@ -360,6 +363,15 @@ export class Bank implements BankForHealth { return this._oracleLastUpdatedSlot; } + get oracleProvider(): OracleProvider { + if (!this._oracleProvider) { + throw new Error( + `Undefined oracleProvider for bank ${this.publicKey} with tokenIndex ${this.tokenIndex}!`, + ); + } + return this._oracleProvider; + } + nativeDeposits(): I80F48 { return this.indexedDeposits.mul(this.depositIndex); } diff --git a/ts/client/src/accounts/group.ts b/ts/client/src/accounts/group.ts index 827b2a42b..6bb57c8e0 100644 --- a/ts/client/src/accounts/group.ts +++ b/ts/client/src/accounts/group.ts @@ -19,6 +19,7 @@ import { Bank, MintInfo, TokenIndex } from './bank'; import { isPythOracle, isSwitchboardOracle, + OracleProvider, parseSwitchboardOracle, } from './oracle'; import { BookSide, PerpMarket, PerpMarketIndex } from './perp'; @@ -331,7 +332,7 @@ export class Group { throw new Error( `Undefined accountInfo object in reloadBankOraclePrices for ${bank.oracle}!`, ); - const { price, uiPrice, lastUpdatedSlot } = + const { price, uiPrice, lastUpdatedSlot, provider } = await this.decodePriceFromOracleAi( coder, bank.oracle, @@ -342,6 +343,7 @@ export class Group { bank._price = price; bank._uiPrice = uiPrice; bank._oracleLastUpdatedSlot = lastUpdatedSlot; + bank._oracleProvider = provider; } } } @@ -366,7 +368,7 @@ export class Group { `Undefined ai object in reloadPerpMarketOraclePrices for ${perpMarket.oracle}!`, ); - const { price, uiPrice, lastUpdatedSlot } = + const { price, uiPrice, lastUpdatedSlot, provider } = await this.decodePriceFromOracleAi( coder, perpMarket.oracle, @@ -377,6 +379,7 @@ export class Group { perpMarket._price = price; perpMarket._uiPrice = uiPrice; perpMarket._oracleLastUpdatedSlot = lastUpdatedSlot; + perpMarket._oracleProvider = provider; }), ); } @@ -387,8 +390,13 @@ export class Group { ai: AccountInfo, baseDecimals: number, client: MangoClient, - ): Promise<{ price: I80F48; uiPrice: number; lastUpdatedSlot: number }> { - let price, uiPrice, lastUpdatedSlot; + ): Promise<{ + price: I80F48; + uiPrice: number; + lastUpdatedSlot: number; + provider: OracleProvider; + }> { + let price, uiPrice, lastUpdatedSlot, provider; if ( !BorshAccountsCoder.accountDiscriminator('stubOracle').compare( ai.data.slice(0, 8), @@ -398,11 +406,13 @@ export class Group { price = new I80F48(stubOracle.price.val); uiPrice = this.toUiPrice(price, baseDecimals); lastUpdatedSlot = stubOracle.lastUpdated.val; + provider = OracleProvider.Stub; } else if (isPythOracle(ai)) { const priceData = parsePriceData(ai.data); uiPrice = priceData.previousPrice; price = this.toNativePrice(uiPrice, baseDecimals); lastUpdatedSlot = parseInt(priceData.lastSlot.toString()); + provider = OracleProvider.Pyth; } else if (isSwitchboardOracle(ai)) { const priceData = await parseSwitchboardOracle( ai, @@ -411,12 +421,13 @@ export class Group { uiPrice = priceData.price; price = this.toNativePrice(uiPrice, baseDecimals); lastUpdatedSlot = priceData.lastUpdatedSlot; + provider = OracleProvider.Switchboard; } else { throw new Error( `Unknown oracle provider (parsing not implemented) for oracle ${oracle}, with owner ${ai.owner}!`, ); } - return { price, uiPrice, lastUpdatedSlot }; + return { price, uiPrice, lastUpdatedSlot, provider }; } public async reloadVaults(client: MangoClient): Promise { diff --git a/ts/client/src/accounts/oracle.ts b/ts/client/src/accounts/oracle.ts index 0db7ed24e..431e4fd13 100644 --- a/ts/client/src/accounts/oracle.ts +++ b/ts/client/src/accounts/oracle.ts @@ -13,6 +13,12 @@ const SBV1_MAINNET_PID = new PublicKey( let sbv2DevnetProgram; let sbv2MainnetProgram; +export enum OracleProvider { + Pyth, + Switchboard, + Stub, +} + export class StubOracle { public price: I80F48; public lastUpdated: BN; diff --git a/ts/client/src/accounts/perp.ts b/ts/client/src/accounts/perp.ts index 3ddf74043..a0aec6891 100644 --- a/ts/client/src/accounts/perp.ts +++ b/ts/client/src/accounts/perp.ts @@ -21,6 +21,7 @@ import { } from './bank'; import { Group } from './group'; import { MangoAccount } from './mangoAccount'; +import { OracleProvider } from './oracle'; export type PerpMarketIndex = number & As<'perp-market-index'>; @@ -55,6 +56,8 @@ export class PerpMarket { public _price: I80F48; public _uiPrice: number; public _oracleLastUpdatedSlot: number; + public _oracleProvider: OracleProvider; + public _bids: BookSide; public _asks: BookSide; @@ -265,6 +268,15 @@ export class PerpMarket { return this._oracleLastUpdatedSlot; } + get oracleProvider(): OracleProvider { + if (!this._oracleProvider) { + throw new Error( + `Undefined oracleProvider for perpMarket ${this.publicKey} with marketIndex ${this.perpMarketIndex}!`, + ); + } + return this._oracleProvider; + } + get minOrderSize(): number { return this.baseLotsToUiConverter; }