UNPKG

@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.78 kB
import e from"events";import{fromPairKey as t,toPairKey as a,toDirectionKey as r,isOrderTradable as s}from"../utils/index.js";import{encodedStrategyStrToBN as i,encodedOrderStrToBN as d,encodedOrderBNToStr as n,encodedStrategyBNToStr as o}from"../../utils/serializers/index.js";import{Logger as c}from"../../common/logger/index.js";const h=new c("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(i),e)),{}),this._strategiesById=Object.entries(t.strategiesById).reduce(((e,[t,a])=>(e[t]=i(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)))):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(o),e)),{}),strategiesById:Object.entries(this._strategiesById).reduce(((e,[t,a])=>(e[t]=o(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"))}clear(e=!1){const a=Object.keys(this._strategiesByPair).map(t);this._strategiesByPair={},this._strategiesById={},this._ordersByDirectedPair={},this._latestBlockNumber=0,this._latestTradesByPair={},this._latestTradesByDirectedPair={},this._blocksMetadata=[],e||this.emit("onPairDataChanged",a)}async getStrategiesByPair(e,t){await this._checkAndHandleCacheMiss(e,t);const r=a(e,t);return this._strategiesByPair[r]}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,a])=>t(e))):Object.keys(this._strategiesByPair).map(t)}async getOrdersByPair(e,t,a=!1){await this._checkAndHandleCacheMiss(e,t);const i=r(e,t),d=this._ordersByDirectedPair[i]||{};return a?d:Object.fromEntries(Object.entries(d).filter((([e,t])=>s(t))))}hasCachedPair(e,t){const r=a(e,t);return!!this._strategiesByPair[r]}async getLatestTradeByPair(e,t){await this._checkAndHandleCacheMiss(e,t);const r=a(e,t);return this._latestTradesByPair[r]}async getLatestTradeByDirectedPair(e,t){await this._checkAndHandleCacheMiss(e,t);const a=r(e,t);return this._latestTradesByDirectedPair[a]}getLatestTrades(){return Object.values(this._latestTradesByPair)}getLatestBlockNumber(){return this._latestBlockNumber}async getTradingFeePPMByPair(e,t){await this._checkAndHandleCacheMiss(e,t);const r=a(e,t);return this._tradingFeePPMByPair[r]}get blocksMetadata(){return this._blocksMetadata}set blocksMetadata(e){this._blocksMetadata=e}_addPair(e,t,r){h.debug("Adding pair with",r.length," strategies to cache",e,t);const s=a(e,t);if(this._strategiesByPair[s])throw new Error(`Pair ${s} already cached`);this._strategiesByPair[s]=r,r.forEach((e=>{this._strategiesById[e.id.toString()]=e,this._addStrategyOrders(e)}))}addPair(e,r,s){this._addPair(e,r,s),h.debug("Emitting onPairAddedToCache",e,r),this.emit("onPairAddedToCache",t(a(e,r)))}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,t,r){h.debug("Adding trading fee to pair",e,t,"fee",r);const s=a(e,t);this._tradingFeePPMByPair[s]=r}applyEvents(e,r){const s=new Set;this._setLatestBlockNumber(r);for(const t of e)switch(t.type){case"StrategyCreated":{const e=t.data;this._addStrategy(e),s.add(a(e.token0,e.token1));break}case"StrategyUpdated":{const e=t.data;this._updateStrategy(e),s.add(a(e.token0,e.token1));break}case"StrategyDeleted":{const e=t.data;this._deleteStrategy(e),s.add(a(e.token0,e.token1));break}case"TokensTraded":{const e=t.data;this._setLatestTrade(e),s.add(a(e.sourceToken,e.targetToken));break}case"PairTradingFeePPMUpdated":{const e=t.data;this.addPairFees(e[0],e[1],e[2]);break}}s.size>0&&(h.debug("Emitting onPairDataChanged",s),this.emit("onPairDataChanged",Array.from(s).map(t)))}_setLatestBlockNumber(e){this._latestBlockNumber=e}_setLatestTrade(e){if(!this.hasCachedPair(e.sourceToken,e.targetToken))return void h.error(`Pair ${a(e.sourceToken,e.targetToken)} is not cached, cannot set latest trade`);const t=a(e.sourceToken,e.targetToken);this._latestTradesByPair[t]=e;const s=r(e.sourceToken,e.targetToken);this._latestTradesByDirectedPair[s]=e}_addStrategyOrders(e){for(const t of[[e.token0,e.token1],[e.token1,e.token0]]){const a=r(t[0],t[1]),s=t[0]===e.token0?e.order1:e.order0,i=this._ordersByDirectedPair[a];i?i[e.id.toString()]=s:this._ordersByDirectedPair[a]={[e.id.toString()]:s}}}_removeStrategyOrders(e){for(const t of[[e.token0,e.token1],[e.token1,e.token0]]){const a=r(t[0],t[1]),s=this._ordersByDirectedPair[a];s&&(delete s[e.id.toString()],0===Object.keys(s).length&&delete this._ordersByDirectedPair.key)}}_addStrategy(e){if(!this.hasCachedPair(e.token0,e.token1))return void h.error(`Pair ${a(e.token0,e.token1)} is not cached, cannot add strategy`);const t=a(e.token0,e.token1);if(this._strategiesById[e.id.toString()])return void h.debug(`Strategy ${e.id} already cached, under the pair ${t} - skipping`);const r=this._strategiesByPair[t]||[];r.push(e),this._strategiesByPair[t]=r,this._strategiesById[e.id.toString()]=e,this._addStrategyOrders(e)}_updateStrategy(e){if(!this.hasCachedPair(e.token0,e.token1))return void h.error(`Pair ${a(e.token0,e.token1)} is not cached, cannot update strategy`);const t=a(e.token0,e.token1),r=(this._strategiesByPair[t]||[]).filter((t=>!t.id.eq(e.id)));r.push(e),this._strategiesByPair[t]=r,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 ${a(e.token0,e.token1)} is not cached, cannot delete strategy`);const t=a(e.token0,e.token1);delete this._strategiesById[e.id.toString()];const r=(this._strategiesByPair[t]||[]).filter((t=>!t.id.eq(e.id)));this._strategiesByPair[t]=r,this._removeStrategyOrders(e)}}export{g as ChainCache};