@bancor/carbon-sdk
Version:
The SDK is a READ-ONLY tool, intended to facilitate working with Carbon contracts. It's a convenient wrapper around our matching algorithm, allowing programs and users get a ready to use transaction data that will allow them to manage strategies and fulfi
2 lines (1 loc) • 7.93 kB
JavaScript
import e from"events";import{toPairKey as t,fromPairKey as a,toDirectionKey as i,isOrderTradable as r}from"../utils/index.js";import{encodedStrategyStrToBN as s,encodedOrderStrToBN as d,encodedOrderBNToStr as n,encodedStrategyBNToStr as c}from"../../utils/serializers/index.js";import{Logger as o}from"../../common/logger/index.js";const h=new o("ChainCache.ts");class g extends e{_strategiesByPair={};_strategiesById={};_ordersByDirectedPair={};_latestBlockNumber=0;_latestTradesByPair={};_latestTradesByDirectedPair={};_blocksMetadata=[];_tradingFeePPMByPair={};_isCacheInitialized=!1;_handleCacheMiss;static fromSerialized(e){try{const t=new g;return t._deserialize(e),t}catch(e){h.error("Failed to deserialize cache, returning clear cache",e)}return new g}_deserialize(e){const t=JSON.parse(e),{schemeVersion:a}=t;6===a?"number"==typeof t.latestBlockNumber?(this._strategiesByPair=Object.entries(t.strategiesByPair).reduce(((e,[t,a])=>(e[t]=a.map(s),e)),{}),this._strategiesById=Object.entries(t.strategiesById).reduce(((e,[t,a])=>(e[t]=s(a),e)),{}),this._ordersByDirectedPair=Object.entries(t.ordersByDirectedPair).reduce(((e,[t,a])=>(e[t]=Object.entries(a).reduce(((e,[t,a])=>(e[t]=d(a),e)),{}),e)),{}),this._tradingFeePPMByPair=t.tradingFeePPMByPair,this._latestBlockNumber=t.latestBlockNumber,this._latestTradesByPair=t.latestTradesByPair,this._latestTradesByDirectedPair=t.latestTradesByDirectedPair,t.blocksMetadata&&(this._blocksMetadata=t.blocksMetadata.filter((e=>!!e&&!!e.number&&!!e.hash))),this._isCacheInitialized=!0,h.debug("Cache initialized from serialized data")):h.error("Cached latest block number is not a number, ignoring cache"):h.log("Cache version mismatch, ignoring cache. Expected",6,"got",a,"This may be due to a breaking change in the cache format since it was last persisted.")}serialize(){const e={schemeVersion:6,strategiesByPair:Object.entries(this._strategiesByPair).reduce(((e,[t,a])=>(e[t]=a.map(c),e)),{}),strategiesById:Object.entries(this._strategiesById).reduce(((e,[t,a])=>(e[t]=c(a),e)),{}),ordersByDirectedPair:Object.entries(this._ordersByDirectedPair).reduce(((e,[t,a])=>(e[t]=Object.entries(a).reduce(((e,[t,a])=>(e[t]=n(a),e)),{}),e)),{}),tradingFeePPMByPair:this._tradingFeePPMByPair,latestBlockNumber:this._latestBlockNumber,latestTradesByPair:this._latestTradesByPair,latestTradesByDirectedPair:this._latestTradesByDirectedPair,blocksMetadata:this._blocksMetadata};return JSON.stringify(e)}setCacheMissHandler(e){this._handleCacheMiss=e}async _checkAndHandleCacheMiss(e,t){this._isCacheInitialized||!this._handleCacheMiss||this.hasCachedPair(e,t)||(h.debug("Cache miss for pair",e,t),await this._handleCacheMiss(e,t),h.debug("Cache miss for pair",e,t,"resolved"))}isCacheInitialized(){return this._isCacheInitialized}clear(){this._strategiesByPair={},this._strategiesById={},this._ordersByDirectedPair={},this._latestBlockNumber=0,this._latestTradesByPair={},this._latestTradesByDirectedPair={},this._blocksMetadata=[],this._blocksMetadata=[],this._tradingFeePPMByPair={},this._isCacheInitialized=!1,this.emit("onCacheCleared")}async getStrategiesByPair(e,a){await this._checkAndHandleCacheMiss(e,a);const i=t(e,a);return this._strategiesByPair[i]}async getStrategiesByPairs(e){const t=[];for(const a of e){const e=await this.getStrategiesByPair(a[0],a[1]);e&&t.push({pair:a,strategies:e})}return t}getStrategyById(e){return this._strategiesById[e.toString()]}getCachedPairs(e=!0){return e?Object.entries(this._strategiesByPair).filter((([e,t])=>t.length>0)).map((([e,t])=>a(e))):Object.keys(this._strategiesByPair).map(a)}async getOrdersByPair(e,t,a=!1){await this._checkAndHandleCacheMiss(e,t);const s=i(e,t),d=this._ordersByDirectedPair[s]||{};return a?d:Object.fromEntries(Object.entries(d).filter((([e,t])=>r(t))))}hasCachedPair(e,a){const i=t(e,a);return!!this._strategiesByPair[i]}async getLatestTradeByPair(e,a){await this._checkAndHandleCacheMiss(e,a);const i=t(e,a);return this._latestTradesByPair[i]}async getLatestTradeByDirectedPair(e,t){await this._checkAndHandleCacheMiss(e,t);const a=i(e,t);return this._latestTradesByDirectedPair[a]}getLatestTrades(){return Object.values(this._latestTradesByPair)}getLatestBlockNumber(){return this._latestBlockNumber}async getTradingFeePPMByPair(e,a){await this._checkAndHandleCacheMiss(e,a);const i=t(e,a);return this._tradingFeePPMByPair[i]}get blocksMetadata(){return this._blocksMetadata}set blocksMetadata(e){this._blocksMetadata=e}_addPair(e,a,i){h.debug("Adding pair with",i.length," strategies to cache",e,a);const r=t(e,a);if(this._strategiesByPair[r])throw new Error(`Pair ${r} already cached`);this._strategiesByPair[r]=i,i.forEach((e=>{this._strategiesById[e.id.toString()]=e,this._addStrategyOrders(e)}))}addPair(e,i,r){this._addPair(e,i,r),h.debug("Emitting onPairAddedToCache",e,i),this.emit("onPairAddedToCache",a(t(e,i)))}bulkAddPairs(e){h.debug("Bulk adding pairs",e);for(const t of e)this._addPair(t.pair[0],t.pair[1],t.strategies);e.length>0&&!this._isCacheInitialized&&(this._isCacheInitialized=!0,h.debug("Emitting onCacheInitialized"),this.emit("onCacheInitialized"))}addPairFees(e,a,i){h.debug("Adding trading fee to pair",e,a,"fee",i);const r=t(e,a);this._tradingFeePPMByPair[r]=i}applyEvents(e,i){const r=new Set;this._setLatestBlockNumber(i);for(const a of e)switch(a.type){case"StrategyCreated":{const e=a.data;this._addStrategy(e),r.add(t(e.token0,e.token1));break}case"StrategyUpdated":{const e=a.data;this._updateStrategy(e),r.add(t(e.token0,e.token1));break}case"StrategyDeleted":{const e=a.data;this._deleteStrategy(e),r.add(t(e.token0,e.token1));break}case"TokensTraded":{const e=a.data;this._setLatestTrade(e),r.add(t(e.sourceToken,e.targetToken));break}case"PairTradingFeePPMUpdated":{const e=a.data;this.addPairFees(e[0],e[1],e[2]);break}}r.size>0&&(h.debug("Emitting onPairDataChanged",r),this.emit("onPairDataChanged",Array.from(r).map(a)))}_setLatestBlockNumber(e){this._latestBlockNumber=e}_setLatestTrade(e){if(!this.hasCachedPair(e.sourceToken,e.targetToken))return void h.error(`Pair ${t(e.sourceToken,e.targetToken)} is not cached, cannot set latest trade`);const a=t(e.sourceToken,e.targetToken);this._latestTradesByPair[a]=e;const r=i(e.sourceToken,e.targetToken);this._latestTradesByDirectedPair[r]=e}_addStrategyOrders(e){for(const t of[[e.token0,e.token1],[e.token1,e.token0]]){const a=i(t[0],t[1]),r=t[0]===e.token0?e.order1:e.order0,s=this._ordersByDirectedPair[a];s?s[e.id.toString()]=r:this._ordersByDirectedPair[a]={[e.id.toString()]:r}}}_removeStrategyOrders(e){for(const t of[[e.token0,e.token1],[e.token1,e.token0]]){const a=i(t[0],t[1]),r=this._ordersByDirectedPair[a];r&&(delete r[e.id.toString()],0===Object.keys(r).length&&delete this._ordersByDirectedPair.key)}}_addStrategy(e){if(!this.hasCachedPair(e.token0,e.token1))return void h.error(`Pair ${t(e.token0,e.token1)} is not cached, cannot add strategy`);const a=t(e.token0,e.token1);if(this._strategiesById[e.id.toString()])return void h.debug(`Strategy ${e.id} already cached, under the pair ${a} - skipping`);const i=this._strategiesByPair[a]||[];i.push(e),this._strategiesByPair[a]=i,this._strategiesById[e.id.toString()]=e,this._addStrategyOrders(e)}_updateStrategy(e){if(!this.hasCachedPair(e.token0,e.token1))return void h.error(`Pair ${t(e.token0,e.token1)} is not cached, cannot update strategy`);const a=t(e.token0,e.token1),i=(this._strategiesByPair[a]||[]).filter((t=>!t.id.eq(e.id)));i.push(e),this._strategiesByPair[a]=i,this._strategiesById[e.id.toString()]=e,this._removeStrategyOrders(e),this._addStrategyOrders(e)}_deleteStrategy(e){if(!this.hasCachedPair(e.token0,e.token1))return void h.error(`Pair ${t(e.token0,e.token1)} is not cached, cannot delete strategy`);const a=t(e.token0,e.token1);delete this._strategiesById[e.id.toString()];const i=(this._strategiesByPair[a]||[]).filter((t=>!t.id.eq(e.id)));this._strategiesByPair[a]=i,this._removeStrategyOrders(e)}}export{g as ChainCache};