Skip to content

Commit 624dfe5

Browse files
committed
fix: missing doge deployment causes issues with finding prices
1 parent 431a0ee commit 624dfe5

File tree

3 files changed

+75
-46
lines changed

3 files changed

+75
-46
lines changed

packages/fasset-indexer-api/src/analytics/dashboard.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { EntityManager, raw, type ORM, ZeroAddress } from "fasset-indexer-core/o
33
import * as Entities from "fasset-indexer-core/entities"
44
import { EVENTS } from "fasset-indexer-core/config"
55
import { unixnow } from "../shared/utils"
6-
import { fassetToUsdPrice } from "./utils/prices"
6+
import { FAssetPriceLoader } from "./utils/prices"
77
import { SharedAnalytics } from "./shared"
88
import { AgentStatistics } from "./statistics"
99
import { MAX_BIPS, PRICE_FACTOR } from "../config/constants"
@@ -27,13 +27,15 @@ const div = (x: bigint, y: bigint) => y == BigInt(0) ? BigInt(0) : x / y
2727
*/
2828
export class DashboardAnalytics extends SharedAnalytics {
2929
protected lookup: ContractLookup
30+
private price: FAssetPriceLoader
3031
private statistics: AgentStatistics
3132
private zeroAddressId: number | null = null
3233
private supportedFAssets: FAsset[]
3334

3435
constructor(public readonly orm: ORM, public readonly chain: string, addressesJson?: string) {
3536
super(orm)
3637
this.lookup = new ContractLookup(chain, addressesJson)
38+
this.price = new FAssetPriceLoader()
3739
this.statistics = new AgentStatistics(orm)
3840
this.supportedFAssets = FASSETS.filter(x => this.lookup.supportsFAsset(FAssetType[x]))
3941
}
@@ -544,12 +546,16 @@ export class DashboardAnalytics extends SharedAnalytics {
544546
}
545547

546548
protected async aggregateTimeSeries(timeseries: FAssetTimeSeries<bigint>): Promise<TimeSeries<bigint>> {
549+
this.price.clearCache()
547550
const em = this.orm.em.fork()
548551
const acc = {} as { [index: number]: { start: number, end: number, value: bigint } }
549552
for (const [fasset, ts] of Object.entries(timeseries)) {
550-
const [priceMul, priceDiv] = await fassetToUsdPrice(em, FAssetType[fasset as FAsset])
551553
for (const point of ts) {
552-
const value = PRICE_FACTOR * point.value * priceMul / priceDiv
554+
let value = BigInt(0)
555+
if (point.value != BigInt(0)) {
556+
const [priceMul, priceDiv] = await this.price.getFAssetToUsdPrice(em, FAssetType[fasset as FAsset])
557+
value = PRICE_FACTOR * point.value * priceMul / priceDiv
558+
}
553559
if (acc[point.index] === undefined) {
554560
acc[point.index] = { start: point.start, end: point.end, value }
555561
continue
@@ -586,12 +592,16 @@ export class DashboardAnalytics extends SharedAnalytics {
586592
}
587593

588594
protected async aggregateFAssetTimespans(timespans: FAssetTimespan<bigint>): Promise<Timespan<bigint>> {
595+
this.price.clearCache()
589596
const acc: { [timestamp: number]: bigint } = {}
590597
const em = this.orm.em.fork()
591598
for (const [fasset, timespan] of Object.entries(timespans)) {
592-
const [priceMul, priceDiv] = await fassetToUsdPrice(em, FAssetType[fasset as FAsset])
593599
for (const point of timespan) {
594-
const value = PRICE_FACTOR * point.value * priceMul / priceDiv
600+
let value = BigInt(0)
601+
if (point.value != BigInt(0)) {
602+
const [priceMul, priceDiv] = await this.price.getFAssetToUsdPrice(em, FAssetType[fasset as FAsset])
603+
value = PRICE_FACTOR * point.value * priceMul / priceDiv
604+
}
595605
if (acc[point.timestamp] === undefined) {
596606
acc[point.timestamp] = value
597607
continue

packages/fasset-indexer-api/src/analytics/statistics.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,17 @@ import {
66
} from "fasset-indexer-core/entities"
77
import { SharedAnalytics } from "./shared"
88
import { weightedAverage } from "./utils/weighted-average"
9-
import { fassetToUsd, tokenToUsd } from "./utils/prices"
9+
import { FAssetPriceLoader } from "./utils/prices"
1010
import { LIQUIDATION_DURATION_SQL } from "./utils/raw-sql"
1111

1212

1313
export class AgentStatistics extends SharedAnalytics {
14-
constructor(public readonly orm: ORM) { super(orm) }
14+
private price: FAssetPriceLoader
15+
16+
constructor(public readonly orm: ORM) {
17+
super(orm)
18+
this.price = new FAssetPriceLoader()
19+
}
1520

1621
async redemptionDefaultWA(vault: string, now: number, delta: number, lim: number): Promise<[bigint, number]> {
1722
const result = await this.orm.em.fork().createQueryBuilder(RedemptionDefault, 'rd')
@@ -114,11 +119,11 @@ export class AgentStatistics extends SharedAnalytics {
114119
// get usd value of pool yield
115120
const poolYieldFAsset = await this.collateralPoolYieldWA(pool, now, delta, lim)
116121
const vault = await em.findOneOrFail(AgentVault, { collateralPool: { hex: pool }})
117-
const poolYieldUsd = await fassetToUsd(em, vault.fasset, poolYieldFAsset)
122+
const poolYieldUsd = await this.price.fassetToUsd(em, vault.fasset, poolYieldFAsset)
118123
// get usd value of pool collateral
119124
const poolCollateralNat = await this.poolCollateralAt(pool, undefined, now)
120125
const token = await em.findOneOrFail(CollateralTypeAdded, { collateralClass: 1 }, { populate: ['address'] })
121-
const poolCollateralUsd = await tokenToUsd(em, token.address.hex, poolCollateralNat)
126+
const poolCollateralUsd = await this.price.tokenToUsd(em, token.address.hex, poolCollateralNat)
122127
// return
123128
return BigInt(1e5) * poolYieldUsd / poolCollateralUsd
124129
}

packages/fasset-indexer-api/src/analytics/utils/prices.ts

Lines changed: 51 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,58 @@ import { PRICE_FACTOR } from "../../config/constants"
44
import type { EntityManager } from "fasset-indexer-core/orm"
55

66

7-
export function fassetDecimals(fasset: FAssetType): number {
8-
if (fasset == FAssetType.FXRP) {
9-
return 6
10-
} else if (fasset == FAssetType.FBTC) {
11-
return 8
12-
} else if (fasset == FAssetType.FDOGE) {
13-
return 8
14-
} else if (fasset == FAssetType.FLTC) {
15-
return 8
16-
} else if (fasset == FAssetType.FALG) {
17-
return 6
18-
} else {
19-
throw new Error(`Decimals not known for fasset ${FAssetType[fasset]}`)
7+
export class FAssetPriceLoader {
8+
private cache: Map<FAssetType, [bigint, bigint]> = new Map()
9+
10+
async getFAssetToUsdPrice(em: EntityManager, fasset: FAssetType): Promise<[mul: bigint, div: bigint]> {
11+
if (!this.cache.has(fasset)) {
12+
const price = await this.fassetToUsdPrice(em, fasset)
13+
this.cache.set(fasset, price)
14+
}
15+
return this.cache.get(fasset)
16+
}
17+
18+
// doesn't need caching yet
19+
async fassetToUsd(em: EntityManager, fasset: FAssetType, amount: bigint): Promise<bigint> {
20+
const [mul, div] = await this.fassetToUsdPrice(em, fasset)
21+
return PRICE_FACTOR * amount * mul / div
22+
}
23+
24+
// doens't need caching yet
25+
async tokenToUsd(em: EntityManager, address: string, amount: bigint): Promise<bigint> {
26+
const [mul, div] = await this.tokenToUsdPrice(em, address)
27+
return PRICE_FACTOR * amount * mul / div
28+
}
29+
30+
protected fassetDecimals(fasset: FAssetType): number {
31+
if (fasset == FAssetType.FXRP) {
32+
return 6
33+
} else if (fasset == FAssetType.FBTC) {
34+
return 8
35+
} else if (fasset == FAssetType.FDOGE) {
36+
return 8
37+
} else if (fasset == FAssetType.FLTC) {
38+
return 8
39+
} else if (fasset == FAssetType.FALG) {
40+
return 6
41+
} else {
42+
throw new Error(`Decimals not known for fasset ${FAssetType[fasset]}`)
43+
}
44+
}
45+
46+
protected async fassetToUsdPrice(em: EntityManager, fasset: FAssetType): Promise<[mul: bigint, div: bigint]> {
47+
if (fasset == FAssetType.FSIMCOINX || fasset == FAssetType.FLTC || fasset == FAssetType.FALG) {
48+
return [ BigInt(0), BigInt(1) ]
49+
}
50+
const fassetToken = await em.findOneOrFail(CollateralTypeAdded, { fasset })
51+
const fassetPrice = await em.findOneOrFail(FtsoPrice, { symbol: fassetToken.assetFtsoSymbol })
52+
const fassetTokenDecimals = this.fassetDecimals(fasset)
53+
return [ fassetPrice.price, BigInt(10) ** BigInt(fassetPrice.decimals + fassetTokenDecimals) ]
2054
}
21-
}
2255

23-
export async function fassetToUsdPrice(em: EntityManager, fasset: FAssetType): Promise<[mul: bigint, div: bigint]> {
24-
if (fasset == FAssetType.FSIMCOINX || fasset == FAssetType.FLTC || fasset == FAssetType.FALG) {
25-
return [ BigInt(0), BigInt(1) ]
56+
protected async tokenToUsdPrice(em: EntityManager, address: string): Promise<[mul: bigint, div: bigint]> {
57+
const token = await em.findOneOrFail(CollateralTypeAdded, { address: { hex: address }})
58+
const price = await em.findOneOrFail(FtsoPrice, { symbol: token.tokenFtsoSymbol })
59+
return [ price.price, BigInt(10) ** BigInt(price.decimals + token.decimals) ]
2660
}
27-
const fassetToken = await em.findOneOrFail(CollateralTypeAdded, { fasset })
28-
const fassetPrice = await em.findOneOrFail(FtsoPrice, { symbol: fassetToken.assetFtsoSymbol })
29-
const fassetTokenDecimals = fassetDecimals(fasset)
30-
return [ fassetPrice.price, BigInt(10) ** BigInt(fassetPrice.decimals + fassetTokenDecimals) ]
31-
}
32-
33-
export async function tokenToUsdPrice(em: EntityManager, address: string): Promise<[mul: bigint, div: bigint]> {
34-
const token = await em.findOneOrFail(CollateralTypeAdded, { address: { hex: address }})
35-
const price = await em.findOneOrFail(FtsoPrice, { symbol: token.tokenFtsoSymbol })
36-
return [ price.price, BigInt(10) ** BigInt(price.decimals + token.decimals) ]
37-
}
38-
39-
export async function fassetToUsd(em: EntityManager, fasset: FAssetType, amount: bigint): Promise<bigint> {
40-
const [mul, div] = await fassetToUsdPrice(em, fasset)
41-
return PRICE_FACTOR * amount * mul / div
42-
}
43-
44-
export async function tokenToUsd(em: EntityManager, address: string, amount: bigint): Promise<bigint> {
45-
const [mul, div] = await tokenToUsdPrice(em, address)
46-
return PRICE_FACTOR * amount * mul / div
4761
}

0 commit comments

Comments
 (0)