@kamino-finance/klend-sdk 2.13.2 → 2.13.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"oracle.js","sourceRoot":"","sources":["../../src/utils/oracle.ts"],"names":[],"mappings":"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","sourcesContent":["import { parsePriceData } from '@pythnetwork/client';\nimport { AccountInfo, Connection, PublicKey } from '@solana/web3.js';\nimport Decimal from 'decimal.js';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { OraclePrices, Scope } from '@hubbleprotocol/scope-sdk';\nimport { isNotNullPubkey, PubkeyHashMap, PublicKeySet } from './pubkey';\nimport { parseTokenSymbol } from '../classes';\nimport SwitchboardProgram from '@switchboard-xyz/sbv2-lite';\nimport { Reserve } from '../lib';\nimport { batchFetch } from '@hubbleprotocol/kamino-sdk';\nimport BN from 'bn.js';\n\nconst SWITCHBOARD_V2_PROGRAM_ID = new PublicKey('SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f');\n\n// validate price confidence - confidence/price ratio should be less than 2%\nexport const MAX_CONFIDENCE_PERCENTAGE: Decimal = new Decimal('2');\n\n/// Confidence factor is used to scale the confidence value to a value that can be compared to the price.\nexport const CONFIDENCE_FACTOR: Decimal = new Decimal('100').div(MAX_CONFIDENCE_PERCENTAGE);\n\nconst getScopeAddress = () => {\n return 'HFn8GnPADiny6XqUoWE8uRPPxb29ikn4yTuPa9MF2fWJ';\n};\n\nexport type TokenOracleData = {\n mintAddress: PublicKey;\n decimals: Decimal;\n price: Decimal;\n timestamp: bigint;\n valid: boolean;\n};\n\nexport type CandidatePrice = {\n price: Decimal;\n timestamp: bigint;\n valid: boolean;\n};\n\n// TODO: Add freshness of the latest price to match sc logic\nexport async function getTokenOracleData(\n connection: Connection,\n reserves: Reserve[]\n): Promise<Array<[Reserve, TokenOracleData | undefined]>> {\n const allOracleAccounts = await getAllOracleAccounts(connection, reserves);\n const tokenOracleDataForReserves: Array<[Reserve, TokenOracleData | undefined]> = [];\n const pythCache = new PubkeyHashMap<PublicKey, PythPrices>();\n const switchboardCache = new PubkeyHashMap<PublicKey, CandidatePrice>();\n const scopeCache = new PubkeyHashMap<PublicKey, OraclePrices>();\n let switchboardV2: SwitchboardProgram | undefined;\n for (const reserve of reserves) {\n let currentBest: CandidatePrice | undefined = undefined;\n const oracle = {\n pythAddress: reserve.config.tokenInfo.pythConfiguration.price,\n switchboardFeedAddress: reserve.config.tokenInfo.switchboardConfiguration.priceAggregator,\n switchboardTwapAddress: reserve.config.tokenInfo.switchboardConfiguration.twapAggregator,\n scopeOracleAddress: reserve.config.tokenInfo.scopeConfiguration.priceFeed,\n };\n if (isNotNullPubkey(oracle.pythAddress)) {\n const pythPrices = cacheOrGetPythPrices(oracle.pythAddress, pythCache, allOracleAccounts);\n if (pythPrices && pythPrices.spot) {\n currentBest = getBestPrice(currentBest, pythPrices.spot);\n }\n }\n if (isNotNullPubkey(oracle.switchboardFeedAddress)) {\n if (!switchboardV2) {\n switchboardV2 = await SwitchboardProgram.loadMainnet(connection);\n }\n const switchboardPrice = cacheOrGetSwitchboardPrice(\n oracle.switchboardFeedAddress,\n switchboardCache,\n allOracleAccounts,\n switchboardV2\n );\n if (switchboardPrice) {\n currentBest = getBestPrice(currentBest, switchboardPrice);\n }\n }\n\n if (isNotNullPubkey(oracle.scopeOracleAddress)) {\n const scopePrice = cacheOrGetScopePrice(\n oracle.scopeOracleAddress,\n scopeCache,\n allOracleAccounts,\n reserve.config.tokenInfo.scopeConfiguration.priceChain\n );\n if (scopePrice) {\n currentBest = getBestPrice(currentBest, scopePrice);\n }\n }\n\n if (!currentBest) {\n console.error(`No price found for reserve: ${parseTokenSymbol(reserve.config.tokenInfo.name)}`);\n tokenOracleDataForReserves.push([reserve, undefined]);\n continue;\n }\n const tokenOracleData: TokenOracleData = {\n mintAddress: reserve.liquidity.mintPubkey,\n decimals: Decimal.pow(10, reserve.liquidity.mintDecimals.toString()),\n price: new Decimal(currentBest.price),\n timestamp: currentBest.timestamp,\n valid: currentBest.valid,\n };\n tokenOracleDataForReserves.push([reserve, tokenOracleData]);\n }\n return tokenOracleDataForReserves;\n}\n\nexport type AllOracleAccounts = PubkeyHashMap<PublicKey, AccountInfo<Buffer>>;\n\nexport async function getAllOracleAccounts(connection: Connection, reserves: Reserve[]): Promise<AllOracleAccounts> {\n const allAccounts: PublicKey[] = [];\n reserves.forEach((reserve) => {\n if (isNotNullPubkey(reserve.config.tokenInfo.pythConfiguration.price)) {\n allAccounts.push(reserve.config.tokenInfo.pythConfiguration.price);\n }\n if (isNotNullPubkey(reserve.config.tokenInfo.switchboardConfiguration.priceAggregator)) {\n allAccounts.push(reserve.config.tokenInfo.switchboardConfiguration.priceAggregator);\n }\n if (isNotNullPubkey(reserve.config.tokenInfo.switchboardConfiguration.twapAggregator)) {\n allAccounts.push(reserve.config.tokenInfo.switchboardConfiguration.twapAggregator);\n }\n if (isNotNullPubkey(reserve.config.tokenInfo.scopeConfiguration.priceFeed)) {\n allAccounts.push(reserve.config.tokenInfo.scopeConfiguration.priceFeed);\n }\n });\n const allAccountsDeduped = dedupKeys(allAccounts);\n const allAccs = await batchFetch(allAccountsDeduped, (chunk) => connection.getMultipleAccountsInfo(chunk));\n const allAccsMap = new PubkeyHashMap<PublicKey, AccountInfo<Buffer>>();\n allAccs.forEach((acc, i) => {\n if (acc) {\n allAccsMap.set(allAccountsDeduped[i], acc);\n }\n });\n return allAccsMap;\n}\n\nfunction dedupKeys(keys: PublicKey[]): PublicKey[] {\n return new PublicKeySet(keys).toArray();\n}\n\nexport type PythPrices = {\n spot?: CandidatePrice;\n twap?: CandidatePrice;\n};\n\n/**\n * Get pyth price from cache or fetch if not available\n * @param oracle oracle address\n * @param cache pyth cache\n * @param oracleAccounts all oracle accounts\n */\nexport function cacheOrGetPythPrices(\n oracle: PublicKey,\n cache: Map<PublicKey, PythPrices>,\n oracleAccounts: AllOracleAccounts\n): PythPrices | null {\n const prices: PythPrices = {};\n const cached = cache.get(oracle);\n if (cached) {\n return cached;\n } else {\n const result = oracleAccounts.get(oracle);\n if (result) {\n try {\n const { price, timestamp, emaPrice, previousPrice, previousTimestamp, confidence } = parsePriceData(\n result.data\n );\n if (price) {\n const px = new Decimal(price);\n prices.spot = {\n price: px,\n timestamp,\n valid: validatePythPx(px, confidence),\n };\n } else {\n prices.spot = {\n price: new Decimal(previousPrice),\n timestamp: previousTimestamp,\n valid: false,\n };\n }\n if (emaPrice !== undefined && emaPrice !== null) {\n prices.twap = {\n price: new Decimal(emaPrice.value),\n timestamp,\n valid: true,\n };\n }\n if (prices.spot || prices.twap) {\n cache.set(oracle, prices);\n }\n } catch (error) {\n console.error(`Error parsing pyth price account ${oracle.toString()} data`, error);\n return null;\n }\n } else {\n return null;\n }\n }\n return prices;\n}\n\n/**\n * Get switchboard price from cache or fetch if not available\n * @param oracle oracle address\n * @param switchboardCache cache for oracle prices\n * @param oracleAccounts all oracle accounts\n * @param switchboardV2 loaded switchboard program\n */\nexport function cacheOrGetSwitchboardPrice(\n oracle: PublicKey,\n switchboardCache: Map<PublicKey, CandidatePrice>,\n oracleAccounts: AllOracleAccounts,\n switchboardV2: SwitchboardProgram\n): CandidatePrice | null {\n const cached = switchboardCache.get(oracle);\n if (cached) {\n return cached;\n } else {\n const info = oracleAccounts.get(oracle);\n if (info) {\n if (info.owner.equals(SWITCHBOARD_V2_PROGRAM_ID)) {\n const agg = switchboardV2.decodeAggregator(info!);\n // @ts-ignore\n const result: Big.Big | null = switchboardV2.getLatestAggregatorValue(agg);\n if (result !== undefined && result !== null) {\n const switchboardPx = new Decimal(result.toString());\n const latestRoundTimestamp: BN = agg.latestConfirmedRound.roundOpenTimestamp;\n const ts = BigInt(latestRoundTimestamp.toString());\n const valid = validateSwitchboardV2Px(agg);\n return {\n price: switchboardPx,\n timestamp: ts,\n valid,\n };\n }\n } else {\n console.error('Unrecognized switchboard owner address: ', info.owner.toString());\n return null;\n }\n }\n }\n return null;\n}\n\n/**\n * Get scope price from cache or fetch if not available\n * @param oracle oracle address\n * @param scopeCache cache for oracle prices\n * @param allOracleAccounts all oracle accounts\n * @param chain scope chain\n */\nexport function cacheOrGetScopePrice(\n oracle: PublicKey,\n scopeCache: Map<PublicKey, OraclePrices>,\n allOracleAccounts: AllOracleAccounts,\n chain: number[]\n): CandidatePrice | null {\n if (!isNotNullPubkey(oracle) || !chain || !Scope.isScopeChainValid(chain)) {\n return null;\n }\n\n const scopePrices = scopeCache.get(oracle);\n if (scopePrices) {\n return scopeChainToCandidatePrice(chain, scopePrices);\n }\n const info = allOracleAccounts.get(oracle);\n if (info) {\n const owner = info.owner.toString();\n if (owner === getScopeAddress()) {\n const prices = OraclePrices.decode(info.data);\n scopeCache.set(oracle, prices);\n return scopeChainToCandidatePrice(chain, prices);\n } else {\n console.error('Unrecognized scope owner address: ', owner);\n }\n }\n\n return null;\n}\n\nfunction getBestPrice(current: CandidatePrice | undefined, next: CandidatePrice): CandidatePrice | undefined {\n if (isBetterPrice(current, next)) {\n return next;\n }\n return current;\n}\n\nfunction isBetterPrice(current: CandidatePrice | undefined, next: CandidatePrice): boolean {\n if (!current) {\n return true;\n }\n if (current.valid && !next.valid) {\n return false;\n }\n if (!current.valid && next.valid) {\n return true;\n }\n return next.timestamp > current.timestamp;\n}\n\nfunction validatePythPx(price: Decimal, confidence: number | undefined): boolean {\n const conf50x = new Decimal(confidence || 0).mul(CONFIDENCE_FACTOR);\n return price.gt(conf50x);\n}\n\nfunction validateSwitchboardV2Px(agg: any): boolean {\n const pxMantissa = new Decimal(agg.latestConfirmedRound.result.mantissa.toString());\n const pxScale = new Decimal(agg.latestConfirmedRound.result.scale.toString());\n const stDevMantissa = new Decimal(agg.latestConfirmedRound.stdDeviation.mantissa.toString());\n const stDevScale = new Decimal(agg.latestConfirmedRound.stdDeviation.scale.toString());\n let conf50xScaled: Decimal;\n if (pxScale.gte(stDevScale)) {\n const scalingFactor = pxScale.sub(stDevScale);\n const conf50x = stDevMantissa.mul(CONFIDENCE_FACTOR);\n conf50xScaled = conf50x.mul(scalingFactor);\n } else {\n const scalingFactor = stDevScale.sub(pxScale);\n const conf50x = stDevMantissa.mul(CONFIDENCE_FACTOR);\n conf50xScaled = conf50x.div(scalingFactor);\n }\n return conf50xScaled.gte(pxMantissa);\n}\n\nfunction scopeChainToCandidatePrice(chain: number[], prices: OraclePrices): CandidatePrice {\n const scopePx = Scope.getPriceFromScopeChain(chain, prices);\n const valid = scopePx.timestamp.gt('0'); // scope prices are pre-validated\n return {\n price: scopePx.price,\n timestamp: BigInt(scopePx.timestamp.toString()),\n valid,\n };\n}\n"]}
1
+ {"version":3,"file":"oracle.js","sourceRoot":"","sources":["../../src/utils/oracle.ts"],"names":[],"mappings":"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","sourcesContent":["import { parsePriceData } from '@pythnetwork/client';\nimport { AccountInfo, Connection, PublicKey } from '@solana/web3.js';\nimport Decimal from 'decimal.js';\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { OraclePrices, Scope } from '@hubbleprotocol/scope-sdk';\nimport { isNotNullPubkey, PubkeyHashMap, PublicKeySet } from './pubkey';\nimport { parseTokenSymbol } from '../classes';\nimport SwitchboardProgram from '@switchboard-xyz/sbv2-lite';\nimport { Reserve } from '../lib';\nimport { batchFetch } from '@hubbleprotocol/kamino-sdk';\nimport BN from 'bn.js';\n\nconst SWITCHBOARD_V2_PROGRAM_ID = new PublicKey('SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f');\n\n// validate price confidence - confidence/price ratio should be less than 2%\nexport const MAX_CONFIDENCE_PERCENTAGE: Decimal = new Decimal('2');\n\n/// Confidence factor is used to scale the confidence value to a value that can be compared to the price.\nexport const CONFIDENCE_FACTOR: Decimal = new Decimal('100').div(MAX_CONFIDENCE_PERCENTAGE);\n\nconst getScopeAddress = () => {\n return 'HFn8GnPADiny6XqUoWE8uRPPxb29ikn4yTuPa9MF2fWJ';\n};\n\nexport type TokenOracleData = {\n mintAddress: PublicKey;\n decimals: Decimal;\n price: Decimal;\n timestamp: bigint;\n valid: boolean;\n};\n\nexport type CandidatePrice = {\n price: Decimal;\n timestamp: bigint;\n valid: boolean;\n};\n\nexport type ScopeRefresh = {\n includeScopeRefresh: boolean;\n scopeFeed: string;\n};\n\n// TODO: Add freshness of the latest price to match sc logic\nexport async function getTokenOracleData(\n connection: Connection,\n reserves: Reserve[]\n): Promise<Array<[Reserve, TokenOracleData | undefined]>> {\n const allOracleAccounts = await getAllOracleAccounts(connection, reserves);\n const tokenOracleDataForReserves: Array<[Reserve, TokenOracleData | undefined]> = [];\n const pythCache = new PubkeyHashMap<PublicKey, PythPrices>();\n const switchboardCache = new PubkeyHashMap<PublicKey, CandidatePrice>();\n const scopeCache = new PubkeyHashMap<PublicKey, OraclePrices>();\n let switchboardV2: SwitchboardProgram | undefined;\n for (const reserve of reserves) {\n let currentBest: CandidatePrice | undefined = undefined;\n const oracle = {\n pythAddress: reserve.config.tokenInfo.pythConfiguration.price,\n switchboardFeedAddress: reserve.config.tokenInfo.switchboardConfiguration.priceAggregator,\n switchboardTwapAddress: reserve.config.tokenInfo.switchboardConfiguration.twapAggregator,\n scopeOracleAddress: reserve.config.tokenInfo.scopeConfiguration.priceFeed,\n };\n if (isNotNullPubkey(oracle.pythAddress)) {\n const pythPrices = cacheOrGetPythPrices(oracle.pythAddress, pythCache, allOracleAccounts);\n if (pythPrices && pythPrices.spot) {\n currentBest = getBestPrice(currentBest, pythPrices.spot);\n }\n }\n if (isNotNullPubkey(oracle.switchboardFeedAddress)) {\n if (!switchboardV2) {\n switchboardV2 = await SwitchboardProgram.loadMainnet(connection);\n }\n const switchboardPrice = cacheOrGetSwitchboardPrice(\n oracle.switchboardFeedAddress,\n switchboardCache,\n allOracleAccounts,\n switchboardV2\n );\n if (switchboardPrice) {\n currentBest = getBestPrice(currentBest, switchboardPrice);\n }\n }\n\n if (isNotNullPubkey(oracle.scopeOracleAddress)) {\n const scopePrice = cacheOrGetScopePrice(\n oracle.scopeOracleAddress,\n scopeCache,\n allOracleAccounts,\n reserve.config.tokenInfo.scopeConfiguration.priceChain\n );\n if (scopePrice) {\n currentBest = getBestPrice(currentBest, scopePrice);\n }\n }\n\n if (!currentBest) {\n console.error(`No price found for reserve: ${parseTokenSymbol(reserve.config.tokenInfo.name)}`);\n tokenOracleDataForReserves.push([reserve, undefined]);\n continue;\n }\n const tokenOracleData: TokenOracleData = {\n mintAddress: reserve.liquidity.mintPubkey,\n decimals: Decimal.pow(10, reserve.liquidity.mintDecimals.toString()),\n price: new Decimal(currentBest.price),\n timestamp: currentBest.timestamp,\n valid: currentBest.valid,\n };\n tokenOracleDataForReserves.push([reserve, tokenOracleData]);\n }\n return tokenOracleDataForReserves;\n}\n\nexport type AllOracleAccounts = PubkeyHashMap<PublicKey, AccountInfo<Buffer>>;\n\nexport async function getAllOracleAccounts(connection: Connection, reserves: Reserve[]): Promise<AllOracleAccounts> {\n const allAccounts: PublicKey[] = [];\n reserves.forEach((reserve) => {\n if (isNotNullPubkey(reserve.config.tokenInfo.pythConfiguration.price)) {\n allAccounts.push(reserve.config.tokenInfo.pythConfiguration.price);\n }\n if (isNotNullPubkey(reserve.config.tokenInfo.switchboardConfiguration.priceAggregator)) {\n allAccounts.push(reserve.config.tokenInfo.switchboardConfiguration.priceAggregator);\n }\n if (isNotNullPubkey(reserve.config.tokenInfo.switchboardConfiguration.twapAggregator)) {\n allAccounts.push(reserve.config.tokenInfo.switchboardConfiguration.twapAggregator);\n }\n if (isNotNullPubkey(reserve.config.tokenInfo.scopeConfiguration.priceFeed)) {\n allAccounts.push(reserve.config.tokenInfo.scopeConfiguration.priceFeed);\n }\n });\n const allAccountsDeduped = dedupKeys(allAccounts);\n const allAccs = await batchFetch(allAccountsDeduped, (chunk) => connection.getMultipleAccountsInfo(chunk));\n const allAccsMap = new PubkeyHashMap<PublicKey, AccountInfo<Buffer>>();\n allAccs.forEach((acc, i) => {\n if (acc) {\n allAccsMap.set(allAccountsDeduped[i], acc);\n }\n });\n return allAccsMap;\n}\n\nfunction dedupKeys(keys: PublicKey[]): PublicKey[] {\n return new PublicKeySet(keys).toArray();\n}\n\nexport type PythPrices = {\n spot?: CandidatePrice;\n twap?: CandidatePrice;\n};\n\n/**\n * Get pyth price from cache or fetch if not available\n * @param oracle oracle address\n * @param cache pyth cache\n * @param oracleAccounts all oracle accounts\n */\nexport function cacheOrGetPythPrices(\n oracle: PublicKey,\n cache: Map<PublicKey, PythPrices>,\n oracleAccounts: AllOracleAccounts\n): PythPrices | null {\n const prices: PythPrices = {};\n const cached = cache.get(oracle);\n if (cached) {\n return cached;\n } else {\n const result = oracleAccounts.get(oracle);\n if (result) {\n try {\n const { price, timestamp, emaPrice, previousPrice, previousTimestamp, confidence } = parsePriceData(\n result.data\n );\n if (price) {\n const px = new Decimal(price);\n prices.spot = {\n price: px,\n timestamp,\n valid: validatePythPx(px, confidence),\n };\n } else {\n prices.spot = {\n price: new Decimal(previousPrice),\n timestamp: previousTimestamp,\n valid: false,\n };\n }\n if (emaPrice !== undefined && emaPrice !== null) {\n prices.twap = {\n price: new Decimal(emaPrice.value),\n timestamp,\n valid: true,\n };\n }\n if (prices.spot || prices.twap) {\n cache.set(oracle, prices);\n }\n } catch (error) {\n console.error(`Error parsing pyth price account ${oracle.toString()} data`, error);\n return null;\n }\n } else {\n return null;\n }\n }\n return prices;\n}\n\n/**\n * Get switchboard price from cache or fetch if not available\n * @param oracle oracle address\n * @param switchboardCache cache for oracle prices\n * @param oracleAccounts all oracle accounts\n * @param switchboardV2 loaded switchboard program\n */\nexport function cacheOrGetSwitchboardPrice(\n oracle: PublicKey,\n switchboardCache: Map<PublicKey, CandidatePrice>,\n oracleAccounts: AllOracleAccounts,\n switchboardV2: SwitchboardProgram\n): CandidatePrice | null {\n const cached = switchboardCache.get(oracle);\n if (cached) {\n return cached;\n } else {\n const info = oracleAccounts.get(oracle);\n if (info) {\n if (info.owner.equals(SWITCHBOARD_V2_PROGRAM_ID)) {\n const agg = switchboardV2.decodeAggregator(info!);\n // @ts-ignore\n const result: Big.Big | null = switchboardV2.getLatestAggregatorValue(agg);\n if (result !== undefined && result !== null) {\n const switchboardPx = new Decimal(result.toString());\n const latestRoundTimestamp: BN = agg.latestConfirmedRound.roundOpenTimestamp;\n const ts = BigInt(latestRoundTimestamp.toString());\n const valid = validateSwitchboardV2Px(agg);\n return {\n price: switchboardPx,\n timestamp: ts,\n valid,\n };\n }\n } else {\n console.error('Unrecognized switchboard owner address: ', info.owner.toString());\n return null;\n }\n }\n }\n return null;\n}\n\n/**\n * Get scope price from cache or fetch if not available\n * @param oracle oracle address\n * @param scopeCache cache for oracle prices\n * @param allOracleAccounts all oracle accounts\n * @param chain scope chain\n */\nexport function cacheOrGetScopePrice(\n oracle: PublicKey,\n scopeCache: Map<PublicKey, OraclePrices>,\n allOracleAccounts: AllOracleAccounts,\n chain: number[]\n): CandidatePrice | null {\n if (!isNotNullPubkey(oracle) || !chain || !Scope.isScopeChainValid(chain)) {\n return null;\n }\n\n const scopePrices = scopeCache.get(oracle);\n if (scopePrices) {\n return scopeChainToCandidatePrice(chain, scopePrices);\n }\n const info = allOracleAccounts.get(oracle);\n if (info) {\n const owner = info.owner.toString();\n if (owner === getScopeAddress()) {\n const prices = OraclePrices.decode(info.data);\n scopeCache.set(oracle, prices);\n return scopeChainToCandidatePrice(chain, prices);\n } else {\n console.error('Unrecognized scope owner address: ', owner);\n }\n }\n\n return null;\n}\n\nfunction getBestPrice(current: CandidatePrice | undefined, next: CandidatePrice): CandidatePrice | undefined {\n if (isBetterPrice(current, next)) {\n return next;\n }\n return current;\n}\n\nfunction isBetterPrice(current: CandidatePrice | undefined, next: CandidatePrice): boolean {\n if (!current) {\n return true;\n }\n if (current.valid && !next.valid) {\n return false;\n }\n if (!current.valid && next.valid) {\n return true;\n }\n return next.timestamp > current.timestamp;\n}\n\nfunction validatePythPx(price: Decimal, confidence: number | undefined): boolean {\n const conf50x = new Decimal(confidence || 0).mul(CONFIDENCE_FACTOR);\n return price.gt(conf50x);\n}\n\nfunction validateSwitchboardV2Px(agg: any): boolean {\n const pxMantissa = new Decimal(agg.latestConfirmedRound.result.mantissa.toString());\n const pxScale = new Decimal(agg.latestConfirmedRound.result.scale.toString());\n const stDevMantissa = new Decimal(agg.latestConfirmedRound.stdDeviation.mantissa.toString());\n const stDevScale = new Decimal(agg.latestConfirmedRound.stdDeviation.scale.toString());\n let conf50xScaled: Decimal;\n if (pxScale.gte(stDevScale)) {\n const scalingFactor = pxScale.sub(stDevScale);\n const conf50x = stDevMantissa.mul(CONFIDENCE_FACTOR);\n conf50xScaled = conf50x.mul(scalingFactor);\n } else {\n const scalingFactor = stDevScale.sub(pxScale);\n const conf50x = stDevMantissa.mul(CONFIDENCE_FACTOR);\n conf50xScaled = conf50x.div(scalingFactor);\n }\n return conf50xScaled.gte(pxMantissa);\n}\n\nfunction scopeChainToCandidatePrice(chain: number[], prices: OraclePrices): CandidatePrice {\n const scopePx = Scope.getPriceFromScopeChain(chain, prices);\n const valid = scopePx.timestamp.gt('0'); // scope prices are pre-validated\n return {\n price: scopePx.price,\n timestamp: BigInt(scopePx.timestamp.toString()),\n valid,\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kamino-finance/klend-sdk",
3
- "version": "2.13.2",
3
+ "version": "2.13.4",
4
4
  "description": "Typescript SDK for interacting with the Kamino Lending (klend) protocol",
5
5
  "repository": {
6
6
  "type": "git",