@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.3 kB
JavaScript
import e from"events";import{fromPairKey as t,toPairKey as r,toDirectionKey as a,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={};_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:r}=t;6===r?"number"==typeof t.latestBlockNumber?(this._strategiesByPair=Object.entries(t.strategiesByPair).reduce(((e,[t,r])=>(e[t]=r.map(i),e)),{}),this._strategiesById=Object.entries(t.strategiesById).reduce(((e,[t,r])=>(e[t]=i(r),e)),{}),this._ordersByDirectedPair=Object.entries(t.ordersByDirectedPair).reduce(((e,[t,r])=>(e[t]=Object.entries(r).reduce(((e,[t,r])=>(e[t]=d(r),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",r,"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,r])=>(e[t]=r.map(o),e)),{}),strategiesById:Object.entries(this._strategiesById).reduce(((e,[t,r])=>(e[t]=o(r),e)),{}),ordersByDirectedPair:Object.entries(this._ordersByDirectedPair).reduce(((e,[t,r])=>(e[t]=Object.entries(r).reduce(((e,[t,r])=>(e[t]=n(r),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._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 r=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",r)}async getStrategiesByPair(e,t){await this._checkAndHandleCacheMiss(e,t);const a=r(e,t);return this._strategiesByPair[a]}getStrategyById(e){return this._strategiesById[e.toString()]}getCachedPairs(e=!0){return e?Object.entries(this._strategiesByPair).filter((([e,t])=>t.length>0)).map((([e,r])=>t(e))):Object.keys(this._strategiesByPair).map(t)}async getOrdersByPair(e,t,r=!1){await this._checkAndHandleCacheMiss(e,t);const i=a(e,t),d=this._ordersByDirectedPair[i]||{};return r?d:Object.fromEntries(Object.entries(d).filter((([e,t])=>s(t))))}hasCachedPair(e,t){const a=r(e,t);return!!this._strategiesByPair[a]}async getLatestTradeByPair(e,t){await this._checkAndHandleCacheMiss(e,t);const a=r(e,t);return this._latestTradesByPair[a]}async getLatestTradeByDirectedPair(e,t){await this._checkAndHandleCacheMiss(e,t);const r=a(e,t);return this._latestTradesByDirectedPair[r]}getLatestTrades(){return Object.values(this._latestTradesByPair)}getLatestBlockNumber(){return this._latestBlockNumber}async getTradingFeePPMByPair(e,t){await this._checkAndHandleCacheMiss(e,t);const a=r(e,t);return this._tradingFeePPMByPair[a]}get blocksMetadata(){return this._blocksMetadata}set blocksMetadata(e){this._blocksMetadata=e}addPair(e,a,s,i=!1){h.debug("Adding pair with",s.length," strategies to cache",e,a);const d=r(e,a);if(this._strategiesByPair[d])throw new Error(`Pair ${d} already cached`);this._strategiesByPair[d]=s,s.forEach((e=>{this._strategiesById[e.id.toString()]=e,this._addStrategyOrders(e)})),i||(h.debug("Emitting onPairAddedToCache",e,a),this.emit("onPairAddedToCache",t(d)))}addPairFees(e,t,a){h.debug("Adding trading fee to pair",e,t,"fee",a);const s=r(e,t);this._tradingFeePPMByPair[s]=a}applyBatchedUpdates(e,a,s,i,d,n){h.debug("Applying batched updates to cache",{latestBlockNumber:e,latestFeeUpdates:a,latestTrades:s,createdStrategies:i,updatedStrategies:d,deletedStrategies:n});const o=new Set;s.forEach((e=>{this._setLatestTrade(e),o.add(r(e.sourceToken,e.targetToken))})),i.forEach((e=>{this._addStrategy(e),o.add(r(e.token0,e.token1))})),d.forEach((e=>{this._updateStrategy(e),o.add(r(e.token0,e.token1))})),n.forEach((e=>{this._deleteStrategy(e),o.add(r(e.token0,e.token1))})),a.forEach((([e,t,a])=>{this._tradingFeePPMByPair[r(e,t)]=a})),this._setLatestBlockNumber(e),o.size>0&&(h.debug("Emitting onPairDataChanged",o),this.emit("onPairDataChanged",Array.from(o).map(t)))}_setLatestBlockNumber(e){this._latestBlockNumber=e}_setLatestTrade(e){if(!this.hasCachedPair(e.sourceToken,e.targetToken))throw new Error(`Pair ${r(e.sourceToken,e.targetToken)} is not cached, cannot set latest trade`);const t=r(e.sourceToken,e.targetToken);this._latestTradesByPair[t]=e;const s=a(e.sourceToken,e.targetToken);this._latestTradesByDirectedPair[s]=e}_addStrategyOrders(e){for(const t of[[e.token0,e.token1],[e.token1,e.token0]]){const r=a(t[0],t[1]),s=t[0]===e.token0?e.order1:e.order0,i=this._ordersByDirectedPair[r];i?i[e.id.toString()]=s:this._ordersByDirectedPair[r]={[e.id.toString()]:s}}}_removeStrategyOrders(e){for(const t of[[e.token0,e.token1],[e.token1,e.token0]]){const r=a(t[0],t[1]),s=this._ordersByDirectedPair[r];s&&(delete s[e.id.toString()],0===Object.keys(s).length&&delete this._ordersByDirectedPair.key)}}_addStrategy(e){if(!this.hasCachedPair(e.token0,e.token1))throw new Error(`Pair ${r(e.token0,e.token1)} is not cached, cannot add strategy`);const t=r(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 a=this._strategiesByPair[t]||[];a.push(e),this._strategiesByPair[t]=a,this._strategiesById[e.id.toString()]=e,this._addStrategyOrders(e)}_updateStrategy(e){if(!this.hasCachedPair(e.token0,e.token1))throw new Error(`Pair ${r(e.token0,e.token1)} is not cached, cannot update strategy`);const t=r(e.token0,e.token1),a=(this._strategiesByPair[t]||[]).filter((t=>!t.id.eq(e.id)));a.push(e),this._strategiesByPair[t]=a,this._strategiesById[e.id.toString()]=e,this._removeStrategyOrders(e),this._addStrategyOrders(e)}_deleteStrategy(e){if(!this.hasCachedPair(e.token0,e.token1))throw new Error(`Pair ${r(e.token0,e.token1)} is not cached, cannot delete strategy`);const t=r(e.token0,e.token1);delete this._strategiesById[e.id.toString()];const a=(this._strategiesByPair[t]||[]).filter((t=>!t.id.eq(e.id)));this._strategiesByPair[t]=a,this._removeStrategyOrders(e)}}export{g as ChainCache};