@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) • 6.19 kB
JavaScript
import e from"events";import{fromPairKey as t,toPairKey as i,toDirectionKey as a,isOrderTradable as r}from"../utils/index.js";import{encodedStrategyStrToBN as s,encodedStrategyBigIntToStr as d}from"../../utils/serializers/index.js";import{Logger as n}from"../../common/logger/index.js";const o=new n("ChainCache.ts");class c extends e{_strategiesByPair={};_strategiesById={};_ordersByDirectedPair={};_latestBlockNumber=0;_blocksMetadata=[];_tradingFeePPMByPair={};_isCacheInitialized=!1;_handleCacheMiss;static fromSerialized(e){try{const t=new c;return t._deserialize(e),t}catch(e){o.error("Failed to deserialize cache, returning clear cache",e)}return new c}_deserialize(e){const i=JSON.parse(e),{schemeVersion:a}=i;if(7===a)if("number"==typeof i.latestBlockNumber){for(const[e,a]of Object.entries(i.strategiesByPair)){const[i,r]=t(e);this._addPair(i,r,a.map(s))}this._tradingFeePPMByPair=i.tradingFeePPMByPair,this._latestBlockNumber=i.latestBlockNumber,this._isCacheInitialized=!0,o.debug("Cache initialized from serialized data")}else o.error("Cached latest block number is not a number, ignoring cache");else o.log("Cache version mismatch, ignoring cache. Expected",7,"got",a,"This may be due to a breaking change in the cache format since it was last persisted.")}serialize(){const e={schemeVersion:7,strategiesByPair:Object.entries(this._strategiesByPair).reduce(((e,[t,i])=>(e[t]=i.map(d),e)),{}),tradingFeePPMByPair:this._tradingFeePPMByPair,latestBlockNumber:this._latestBlockNumber};return JSON.stringify(e)}setCacheMissHandler(e){this._handleCacheMiss=e}async _checkAndHandleCacheMiss(e,t){this._isCacheInitialized||!this._handleCacheMiss||this.hasCachedPair(e,t)||(o.debug("Cache miss for pair",e,t),await this._handleCacheMiss(e,t),o.debug("Cache miss for pair",e,t,"resolved"))}isCacheInitialized(){return this._isCacheInitialized}clear(){this._strategiesByPair={},this._strategiesById={},this._ordersByDirectedPair={},this._latestBlockNumber=0,this._blocksMetadata=[],this._blocksMetadata=[],this._tradingFeePPMByPair={},this._isCacheInitialized=!1,this.emit("onCacheCleared")}async getStrategiesByPair(e,t){await this._checkAndHandleCacheMiss(e,t);const a=i(e,t);return this._strategiesByPair[a]}async getStrategiesByPairs(e){const t=[];for(const i of e){const e=await this.getStrategiesByPair(i[0],i[1]);e&&t.push({pair:i,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,i])=>t(e))):Object.keys(this._strategiesByPair).map(t)}async getOrdersByPair(e,t,i=!1){await this._checkAndHandleCacheMiss(e,t);const s=a(e,t),d=this._ordersByDirectedPair[s]||{};return i?d:Object.fromEntries(Object.entries(d).filter((([e,t])=>r(t))))}hasCachedPair(e,t){const a=i(e,t);return!!this._strategiesByPair[a]}getLatestBlockNumber(){return this._latestBlockNumber}async getTradingFeePPMByPair(e,t){await this._checkAndHandleCacheMiss(e,t);const a=i(e,t);return this._tradingFeePPMByPair[a]}get blocksMetadata(){return this._blocksMetadata}set blocksMetadata(e){this._blocksMetadata=e}_addPair(e,t,a){o.debug("Adding pair with",a.length," strategies to cache",e,t);const r=i(e,t);if(this._strategiesByPair[r])throw new Error(`Pair ${r} already cached`);this._strategiesByPair[r]=a,a.forEach((e=>{this._strategiesById[e.id.toString()]=e,this._addStrategyOrders(e)}))}addPair(e,a,r){this._addPair(e,a,r),o.debug("Emitting onPairAddedToCache",e,a),this.emit("onPairAddedToCache",t(i(e,a)))}bulkAddPairs(e){o.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,o.debug("Emitting onCacheInitialized"),this.emit("onCacheInitialized"))}addPairFees(e,t,a){o.debug("Adding trading fee to pair",e,t,"fee",a);const r=i(e,t);this._tradingFeePPMByPair[r]=a}applyEvents(e,a){const r=new Set;this._setLatestBlockNumber(a);for(const t of e)switch(t.type){case"StrategyCreated":{const e=t.data;this._addStrategy(e),r.add(i(e.token0,e.token1));break}case"StrategyUpdated":{const e=t.data;this._updateStrategy(e),r.add(i(e.token0,e.token1));break}case"StrategyDeleted":{const e=t.data;this._deleteStrategy(e),r.add(i(e.token0,e.token1));break}case"PairTradingFeePPMUpdated":{const e=t.data;this.addPairFees(e[0],e[1],e[2]);break}}r.size>0&&(o.debug("Emitting onPairDataChanged",r),this.emit("onPairDataChanged",Array.from(r).map(t)))}_setLatestBlockNumber(e){this._latestBlockNumber=e}_addStrategyOrders(e){for(const t of[[e.token0,e.token1],[e.token1,e.token0]]){const i=a(t[0],t[1]),r=t[0]===e.token0?e.order1:e.order0,s=this._ordersByDirectedPair[i];s?s[e.id.toString()]=r:this._ordersByDirectedPair[i]={[e.id.toString()]:r}}}_removeStrategyOrders(e){for(const t of[[e.token0,e.token1],[e.token1,e.token0]]){const i=a(t[0],t[1]),r=this._ordersByDirectedPair[i];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 o.error(`Pair ${i(e.token0,e.token1)} is not cached, cannot add strategy`);const t=i(e.token0,e.token1);if(this._strategiesById[e.id.toString()])return void o.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))return void o.error(`Pair ${i(e.token0,e.token1)} is not cached, cannot update strategy`);const t=i(e.token0,e.token1),a=(this._strategiesByPair[t]||[]).filter((t=>t.id!==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))return void o.error(`Pair ${i(e.token0,e.token1)} is not cached, cannot delete strategy`);const t=i(e.token0,e.token1);delete this._strategiesById[e.id.toString()];const a=(this._strategiesByPair[t]||[]).filter((t=>t.id!==e.id));this._strategiesByPair[t]=a,this._removeStrategyOrders(e)}}export{c as ChainCache};