UNPKG

@atomiqlabs/sdk-lib

Version:

Basic SDK functionality library for atomiq

88 lines (77 loc) 3.03 kB
import {ISwapPrice} from "./ISwapPrice"; import {ChainIds, MultiChain} from "../../swaps/Swapper"; const DEFAULT_CACHE_DURATION = 10000; export abstract class ICachedSwapPrice<T extends MultiChain> extends ISwapPrice<T> { cache: { [chainIdentifier in keyof T]?: { [tokenAddress: string]: { price: Promise<bigint>, expiry: number } } } = {}; usdCache: { price: Promise<number>, expiry: number }; cacheTimeout: number; protected constructor(maxAllowedFeeDiffPPM: bigint, cacheTimeout?: number) { super(maxAllowedFeeDiffPPM); this.cacheTimeout = cacheTimeout || DEFAULT_CACHE_DURATION; } protected abstract fetchPrice<C extends ChainIds<T>>(chainIdentifier: C, token: string, abortSignal?: AbortSignal): Promise<bigint>; protected abstract fetchUsdPrice(abortSignal?: AbortSignal): Promise<number>; protected getPrice<C extends ChainIds<T>>(chainIdentifier: C, tokenAddress: string, abortSignal?: AbortSignal): Promise<bigint> { const token = tokenAddress.toString(); const chainCache = this.cache[chainIdentifier]; if(chainCache!=null) { const cachedValue = chainCache[token]; if(cachedValue!=null && cachedValue.expiry>Date.now()) { //Cache still fresh return cachedValue.price.catch(e => this.fetchPrice(chainIdentifier, token, abortSignal)); } } //Refresh cache const thisFetch = this.fetchPrice(chainIdentifier, token); this.cache[chainIdentifier] ??= {}; (this.cache[chainIdentifier] as any)[token] = { price: thisFetch, expiry: Date.now()+this.cacheTimeout }; thisFetch.catch(e => { if( this.cache[chainIdentifier]!=null && this.cache[chainIdentifier][token]!=null && this.cache[chainIdentifier][token].price===thisFetch ) delete this.cache[token]; throw e; }); return thisFetch; } /** * Returns BTC price in USD (sats/USD) * * @param abortSignal * @throws {Error} if token is not found */ protected getUsdPrice(abortSignal?: AbortSignal): Promise<number> { if(this.usdCache!=null && this.usdCache.expiry>Date.now()) { //Cache still fresh return this.usdCache.price.catch(e => this.fetchUsdPrice(abortSignal)); } //Refresh cache const thisFetch = this.fetchUsdPrice(); this.usdCache = { price: thisFetch, expiry: Date.now()+this.cacheTimeout }; thisFetch.catch(e => { if( this.usdCache!=null && this.usdCache.price===thisFetch ) delete this.usdCache; throw e; }); return thisFetch; } }