Skip to content

Commit

Permalink
Merge pull request #36 from axone-protocol/fix/apr
Browse files Browse the repository at this point in the history
fix: added type verification for apr
  • Loading branch information
yevhen-burkovskyi authored Jun 19, 2024
2 parents 8b6754c + d1c5453 commit a3f960a
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 54 deletions.
67 changes: 35 additions & 32 deletions src/core/lib/osmosis/osmosis.service.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { BadRequestException, Injectable } from '@nestjs/common';

import { config } from '@core/config/config';
import { createUrlParams } from '@utils/create-url-params';

import { GetHistoricalChartDto } from './dtos/get-historical-chart.dto';
import { Endpoints } from './enums/endpoints.enum';
import { RouteParam } from './enums/route-param.enum';
import { FailedResponse } from './responses/failed.response';
import { GSFResponse } from './responses/generic-success-failed.response';
import { HistoricalChartRes } from './responses/historical-chart.response';
import { HttpService } from '../http.service';
import { TokenInfoResponse } from './responses/token-info.response';
import { McapResponse } from './responses/mcap.response';
import { BadRequestException, Injectable } from "@nestjs/common";

import { config } from "@core/config/config";
import { createUrlParams } from "@utils/create-url-params";

import { GetHistoricalChartDto } from "./dtos/get-historical-chart.dto";
import { Endpoints } from "./enums/endpoints.enum";
import { RouteParam } from "./enums/route-param.enum";
import { FailedResponse } from "./responses/failed.response";
import { GSFResponse } from "./responses/generic-success-failed.response";
import { HistoricalChartRes } from "./responses/historical-chart.response";
import { HttpService } from "../http.service";
import { TokenInfoResponse } from "./responses/token-info.response";
import { McapResponse } from "./responses/mcap.response";
import { Log } from "@core/loggers/log";

@Injectable()
export class OsmosisService {
Expand All @@ -20,38 +21,33 @@ export class OsmosisService {
constructor(private readonly httpService: HttpService) {}

private constructUrl(endpoint: string, params?: string): string {
return `${this.BASE_URL}/${endpoint}${params ? `?${params}` : ''}`;
return `${this.BASE_URL}/${endpoint}${params ? `?${params}` : ""}`;
}

private getWithErrorHandling<T>(url: string): Promise<T> {
return this.errorHandleWrapper(
this.httpService.get.bind(
null,
url,
),
);
return this.errorHandleWrapper(this.httpService.get.bind(null, url));
}

async getHistoricalChart(
payload: GetHistoricalChartDto,
payload: GetHistoricalChartDto
): Promise<HistoricalChartRes> {
const endpoint = Endpoints.HISTORICAL_PRICE.replace(
RouteParam.SYMBOL,
payload.symbol,
payload.symbol
);

return this.getWithErrorHandling(
this.constructUrl(
endpoint,
createUrlParams({ tf: payload.range.toString() }),
),
createUrlParams({ tf: payload.range.toString() })
)
);
}

async getTokenInfo(symbol: string): Promise<TokenInfoResponse[]> {
const endpoint = Endpoints.TOKEN_BY_SYMBOL.replace(
RouteParam.SYMBOL,
symbol,
symbol
);

return this.getWithErrorHandling(this.constructUrl(endpoint));
Expand All @@ -61,10 +57,15 @@ export class OsmosisService {
return this.getWithErrorHandling(this.constructUrl(Endpoints.MARKET_CAP));
}

async getStakingApr(): Promise<number> {
return this.getWithErrorHandling(
this.constructUrl(Endpoints.STAKING_APR),
)
async getStakingApr(): Promise<string> {
const apr: number = await this.getWithErrorHandling(
this.constructUrl(Endpoints.STAKING_APR)
);
if (isNaN(apr)) {
Log.warn(`Got from Osmosis NaN for apr: ${apr}`);
return "0";
}
return apr.toString();
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand All @@ -77,13 +78,15 @@ export class OsmosisService {
}

return response as T;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
throw new BadRequestException(e.message);
}
}

private isFailedResponse<T>(response: GSFResponse<T>): response is FailedResponse {
private isFailedResponse<T>(
response: GSFResponse<T>
): response is FailedResponse {
return (response as FailedResponse).message !== undefined;
}
}
2 changes: 1 addition & 1 deletion src/modules/staking/services/staking.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ export class StakingService implements OnModuleInit {

const dto: GlobalStakedOverviewDto = {
totalValidators: rez[0].pagination.total,
apr: rez[1].toString(),
apr: rez[1],
totalStaked,
bondedTokens: Big(totalStaked).div(rez[2]!.amount).toString(),
};
Expand Down
57 changes: 36 additions & 21 deletions src/modules/token/services/token.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import { HistoricalChartRes } from "@core/lib/osmosis/responses/historical-chart
import Big from "big.js";
import { DBTimeInterval } from "@core/enums/db-time-interval.enum";
import { Range } from "@core/enums/range.enum";
import { HistoricalChartConf, RangeHistoricalChartConf } from "@core/types/range-historical-chart-conf.dto";
import {
HistoricalChartConf,
RangeHistoricalChartConf,
} from "@core/types/range-historical-chart-conf.dto";
import { HistoricalPrice } from "../dtos/historical-price.dto";
import { TimeBucketDto } from "../dtos/time-bucket.dto";
import { Log } from "@core/loggers/log";
Expand All @@ -21,15 +24,15 @@ export class TokenService implements OnModuleInit {
constructor(
private readonly osmosisService: OsmosisService,
private readonly cache: TokenCache,
private readonly prismaService: PrismaService,
) {
private readonly prismaService: PrismaService
) {
this.rangeTimeIntervalMap = new Map([
[Range.ALL, { interval: DBTimeInterval.MONTH }],
[Range.DAY, { interval: DBTimeInterval.TWO_HOUR, count: 12 }],
[Range.WEEK, { interval: DBTimeInterval.SIX_HOUR, count: 28 }],
[Range.MONTH, { interval: DBTimeInterval.DAY, count: 30 }],
[Range.THREE_MONTH, { interval: DBTimeInterval.THREE_DAY, count: 30 }],
[Range.YEAR, { interval: DBTimeInterval.MONTH, count: 12 }]
[Range.YEAR, { interval: DBTimeInterval.MONTH, count: 12 }],
]);
}

Expand All @@ -49,9 +52,16 @@ export class TokenService implements OnModuleInit {
await Promise.all(promises);
}

private async calculateAndCacheTokenHistoricalPrice(range: Range, { interval, count }: HistoricalChartConf) {
private async calculateAndCacheTokenHistoricalPrice(
range: Range,
{ interval, count }: HistoricalChartConf
) {
try {
const historicalPrice = await this.timeBucket(interval, DBOrder.DESC, count);
const historicalPrice = await this.timeBucket(
interval,
DBOrder.DESC,
count
);
await this.cache.setTokenHistoricalPrice(range, historicalPrice);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} catch (e: any) {
Expand All @@ -62,26 +72,26 @@ export class TokenService implements OnModuleInit {
private async timeBucket(
interval: DBTimeInterval,
order: DBOrder,
limit?: number,
limit?: number
): Promise<HistoricalPrice[]> {
const bucket: TimeBucketDto[] = await this.prismaService.$queryRawUnsafe(`
SELECT time_bucket('${interval}', time) as interval, avg(price) as avg_price
FROM historical_prices
GROUP BY interval
ORDER BY interval ${order}
${limit ? `LIMIT ${limit}` : ''};
${limit ? `LIMIT ${limit}` : ""};
`);

return this.fromBucket(bucket);
}

private fromBucket(bucket: TimeBucketDto[]): HistoricalPrice[] {
return bucket.map((item) => ({
time: item.interval,
price: item.avg_price,
}));
}

async fetchAndCacheTokenInfo() {
const res = (await this.osmosisService.getTokenInfo(config.app.token))[0];
const mcap = await this.getMcapByOrder();
Expand All @@ -97,7 +107,7 @@ export class TokenService implements OnModuleInit {
change: mcap!.change,
},
volume: res.volume_24h,
apr: apr.toString(),
apr,
};

await this.cache.cacheTokenInfo(tokenInfoDto);
Expand All @@ -112,13 +122,15 @@ export class TokenService implements OnModuleInit {
time: new Date(),
mcap,
change,
}
},
});
}

private async fetchNewMcap(): Promise<number> {
const mcaps = await this.osmosisService.getMcap();
const tokenMcap = mcaps.find(({ symbol }) => symbol.toLowerCase() === config.app.token);
const tokenMcap = mcaps.find(
({ symbol }) => symbol.toLowerCase() === config.app.token
);
return tokenMcap?.market_cap || 0;
}

Expand All @@ -130,10 +142,13 @@ export class TokenService implements OnModuleInit {
if (currentMcap.mcap === 0) {
change = Big(newMcap).toNumber();
} else {
change = Big(newMcap).minus(currentMcap.mcap).div(currentMcap.mcap).toNumber();
change = Big(newMcap)
.minus(currentMcap.mcap)
.div(currentMcap.mcap)
.toNumber();
}
}

return change;
}

Expand All @@ -151,30 +166,30 @@ export class TokenService implements OnModuleInit {
data: newPrices,
});
}

private async getLastHistoryPrice() {
return this.prismaService.historicalPrices.findFirst({
orderBy: {
time: DBOrder.DESC,
},
});
}

private async fetchDefaultHistoricalChart() {
const res = await this.osmosisService.getHistoricalChart({
symbol: config.app.token,
range: 5,
});
return this.historicalPriceView(res);
}

private async newHistoricalPrices() {
const lastHistory = await this.getLastHistoryPrice();
let historicalChart = await this.fetchDefaultHistoricalChart();

if (lastHistory) {
const index = historicalChart.findIndex(
(chartData) => new Date(chartData.time) > new Date(lastHistory.time),
(chartData) => new Date(chartData.time) > new Date(lastHistory.time)
);

if (index !== -1) {
Expand All @@ -186,11 +201,11 @@ export class TokenService implements OnModuleInit {

return historicalChart;
}

private historicalPriceView(res: HistoricalChartRes) {
return res.map((item) => ({
time: new Date(item.time * 1000),
price: item.close,
}));
}
}
}

0 comments on commit a3f960a

Please sign in to comment.