0xweb
Version:
Contract package manager and other web3 tools
122 lines (103 loc) • 3.71 kB
text/typescript
import { ITokenBase } from '@dequanto/models/IToken';
import { TResultAsync } from '@dequanto/models/TResult';
import { $config } from '@dequanto/utils/$config';
import { $date } from '@dequanto/utils/$date';
import { IOracle, IOracleResult, ISwapOptions } from '../IOracle';
import { Web3ClientFactory } from '@dequanto/clients/Web3ClientFactory';
import { $block } from '@dequanto/utils/$block';
import { $require } from '@dequanto/utils/$require';
import { TPCoingecko } from '@dequanto/tokens/TokenProviders/TPCoingecko';
import { $http } from '@dequanto/utils/$http';
export class CoingeckoOracle implements IOracle {
private config = $config.get<{ key: string, root: string, rateLimit: string }>('oracles.coingecko');
async getPrice(token: ITokenBase, opts?: ISwapOptions): TResultAsync<IOracleResult> {
$require.notNull(this.config?.root, `Coingecko api root path not found in config`);
opts ??= {};
let coingeckoProvider = new TPCoingecko();
let coingeckoToken = await coingeckoProvider.find(token);
if (coingeckoToken == null) {
return { error: new Error(`NOT_FOUND: Token ${token.symbol} not found`) }
}
let date = opts.date;
if (date == null && opts.block) {
let platform = token.platform ?? 'eth';
let client = Web3ClientFactory.get(platform);
let block = await client.getBlock(opts.block);
date = $block.getDate(block);
}
let priceInfo: { price: number, date: Date };
if (date) {
priceInfo = await this.getHistorical(coingeckoToken.id, date);
} else {
priceInfo = await this.getCurrent(coingeckoToken.id);
}
return {
result: {
quote: { symbol: 'USD' },
price: priceInfo.price,
date: priceInfo.date
}
};
}
private async getCurrent (tokenId: string) {
let path = `/simple/price`;
let query = {
ids: tokenId,
vs_currencies:'usd',
include_market_cap: 'false',
include_24hr_vol: 'false',
include_24hr_change:'false',
include_last_updated_at:'true',
precision:'full'
};
let resp = await this.fetch<ICoingeckoCurrentPrice>(path, query);
let data = resp[tokenId];
return {
price: data.usd,
date: new Date(data.last_updated_at * 1000),
};
}
private async getHistorical (tokenId: string, date: Date) {
let dateFormat = 'dd-MM-yyyy';
let path = `/coins/${tokenId}/history`;
let query = {
date: $date.format(date, dateFormat),
localization: 'false'
}
let data = await this.fetch<ICoingeckoHistoryPrice>(path, query);
let price = data.market_data.current_price.usd;
return {
price,
date: date
}
}
private async fetch <TResult> (path: string, query?: { [key: string]: string }) {
let headers = {};
if (this.config.key != null) {
headers['x-cg-pro-api-key'] = this.config.key;
}
let resp = await $http.get<TResult>({
url: `${this.config.root}${path}`,
params: query,
headers
});
return resp.data;
}
}
interface ICoingeckoHistoryPrice {
id: string
symbol: string
name: string
image: { thumb }
market_data: {
current_price: {
usd: number
}
}
}
interface ICoingeckoCurrentPrice {
[id: string]: {
usd: number
last_updated_at: number
}
}