@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) • 11.8 kB
JavaScript
import{formatUnits as e,parseUnits as t,Decimal as a,tenPow as r,BigNumberMax as i,mulDiv as s}from"../../utils/numerics/index.js";import{MatchType as o}from"../../common/types/index.js";import{Decimals as c}from"../../utils/decimals/index.js";import{matchByTargetAmount as d,matchBySourceAmount as n}from"../../trade-matcher/match/index.js";import{getEncodedTradeSourceAmount as g}from"../../trade-matcher/trade/index.js";import{getDepths as l,getMinRate as u,getMaxRate as m}from"../stats/index.js";import{Logger as y}from"../../common/logger/index.js";import{getMinMaxPricesByDecimals as h,decodeStrategy as p,parseStrategy as f,addFee as B,subtractFee as S,calculateOverlappingSellBudget as b,calculateOverlappingBuyBudget as w,buildStrategyObject as P,encodeStrategy as _,normalizeRate as D}from"../utils/index.js";import{decodeOrder as v}from"../../utils/encoders/index.js";import{ordersMapStrToBN as T,matchActionBNToStr as A,ordersMapBNToStr as x,tradeActionStrToBN as k,encodedStrategyStrToBN as z}from"../../utils/serializers/index.js";import{BigNumber as M}from"@ethersproject/bignumber";const O=new y("Toolkit.ts");var R;function j(e){return void 0!==e&&e!==R.reset&&e!==R.maintain}!function(e){e.reset="RESET",e.maintain="MAINTAIN"}(R||(R={}));class q{_api;_decimals;_cache;constructor(e,t,a){O.debug("SDK class constructor called with",arguments),this._api=e,this._cache=t;this._decimals=new c((async e=>await(a?.(e))??await this._api.reader.getDecimalsByAddress(e)))}async getMinMaxPricesByAddresses(e,t){const a=this._decimals,r=await a.fetchDecimals(e),i=await a.fetchDecimals(t);return h(r,i)}static getMatchActions(e,t,a,r=o.Fast,i){const s=T(a);let c;return c=t?d(M.from(e),s,[r],i):n(M.from(e),s,[r],i),c[r]?.map(A)??[]}async hasLiquidityByPair(e,t){O.debug("hasLiquidityByPair called",arguments);const a=await this._cache.getOrdersByPair(e,t);return O.debug("hasLiquidityByPair info:",{orders:a}),Object.keys(a).length>0}async getLiquidityByPair(t,a){O.debug("getLiquidityByPair called",arguments);const r=await this._cache.getOrdersByPair(t,a),i=Object.values(r).reduce(((e,{y:t})=>e.add(t)),M.from(0)),s=await this._decimals.fetchDecimals(a),o=e(i,s);return O.debug("getLiquidityByPair info:",{orders:r,liquidityWei:i,targetToken:a,decimals:s,liquidity:o}),o}async getMaxSourceAmountByPair(t,a){O.debug("getMaxSourceAmountByPair called",arguments);const r=await this._cache.getOrdersByPair(t,a),i=Object.values(r).reduce(((e,t)=>e.add(g(t.y,t))),M.from(0)),s=await this._decimals.fetchDecimals(t),o=e(i,s);return O.debug("getMaxSourceAmountByPair info:",{orders:r,maxSourceAmountWei:i,sourceToken:t,decimals:s,maxSourceAmount:o}),o}async getStrategyById(e){let t;O.debug("getStrategyById called",arguments),this._cache.isCacheInitialized()&&(t=this._cache.getStrategyById(e)),t?O.debug("getStrategyById fetched from cache"):(O.debug("getStrategyById fetching from chain"),t=await this._api.reader.strategy(M.from(e)));const a=p(t),r=await f(a,this._decimals);return O.debug("getStrategyById info:",{id:e,encodedStrategy:t,decodedStrategy:a,strategy:r}),r}async getStrategiesByPair(e,t){let a;O.debug("getStrategiesByPair called",arguments),this._cache.isCacheInitialized()&&(a=await this._cache.getStrategiesByPair(e,t)),a?O.debug("getStrategiesByPair fetched from cache"):(O.debug("getStrategiesByPair fetching from chain"),a=await this._api.reader.strategiesByPair(e,t));const r=a.map(p),i=await Promise.all(r.map((async e=>await f(e,this._decimals))));return O.debug("getStrategiesByPair info:",{token0:e,token1:t,encodedStrategies:a,decodedStrategies:r,strategies:i}),i}async getStrategiesByPairs(e){O.debug("getStrategiesByPairs called",arguments);let t,a=e;a||(a=this._cache.isCacheInitialized()?this._cache.getCachedPairs():await this._api.reader.pairs()),this._cache.isCacheInitialized()?(t=await this._cache.getStrategiesByPairs(a),O.debug("getStrategiesByPairs fetched from cache")):(O.debug("getStrategiesByPairs fetching from chain"),t=await this._api.reader.strategiesByPairs(a));const r=t.map((({pair:e,strategies:t})=>({pair:e,strategies:t.map(p)}))),i=await Promise.all(r.map((async({pair:e,strategies:t})=>({pair:e,strategies:await Promise.all(t.map((async e=>await f(e,this._decimals))))}))));return O.debug("getStrategiesByPairs info:",{pairs:e,pairsToFetch:a,encodedStrategies:t,decodedStrategies:r,strategies:i}),i}async getUserStrategies(e){O.debug("getUserStrategies called",arguments);const t=await this._api.reader.tokensByOwner(e);let a=[],r=t;if(this._cache.isCacheInitialized()&&(r=t.reduce(((e,t)=>{const r=this._cache.getStrategyById(t);return r?a.push(r):e.push(t),e}),[])),r.length>0){const e=await this._api.reader.strategies(r);a=[...a,...e]}const i=a.map(p),s=await Promise.all(i.map((async e=>await f(e,this._decimals))));return O.debug("getUserStrategies info:",{ids:t,encodedStrategies:a,decodedStrategies:i,strategies:s}),s}async getMatchParams(e,a,r,i){O.debug("getMatchParams called",arguments);const s=this._decimals,o=await s.fetchDecimals(e),c=await s.fetchDecimals(a),d=await this._cache.getOrdersByPair(e,a),n=t(r,i?c:o);return{orders:x(d),amountWei:n.toString(),sourceDecimals:o,targetDecimals:c}}async getTradeData(e,t,a,r,i=o.Fast,s){O.debug("getTradeData called",arguments);const{orders:c,amountWei:d}=await this.getMatchParams(e,t,a,r),n=q.getMatchActions(d,r,c,i,s),g=await this.getTradeDataFromActions(e,t,r,n);return O.debug("getTradeData info:",{orders:c,amount:a,amountWei:d,res:g}),g}async getTradeDataFromActions(t,i,s,o){O.debug("getTradeDataFromActions called",arguments);const c=await this._cache.getTradingFeePPMByPair(t,i);if(void 0===c)throw new Error(`tradingFeePPM is undefined for this pair: ${t}-${i}`);const d=this._decimals,n=await d.fetchDecimals(t),g=await d.fetchDecimals(i),l=[],u=[];let m,y,h,p=M.from(0),f=M.from(0);if(o.forEach((t=>{l.push({strategyId:t.id,amount:t.input}),s?u.push({id:t.id,sourceAmount:e(B(t.output,c).floor().toFixed(0),n),targetAmount:e(t.input,g)}):u.push({id:t.id,sourceAmount:e(t.input,n),targetAmount:e(S(t.output,c).floor().toFixed(0),g)}),f=f.add(t.input),p=p.add(t.output)})),s?(m=B(p,c).floor().toFixed(0),y=f.toString()):(m=f.toString(),y=S(p,c).floor().toFixed(0)),new a(m).isZero()||new a(y).isZero())h={tradeActions:l,actionsTokenRes:u,totalSourceAmount:"0",totalTargetAmount:"0",effectiveRate:"0",actionsWei:o};else{const t=new a(y).div(m).times(r(n,g)).toString();h={tradeActions:l,actionsTokenRes:u,totalSourceAmount:e(m,n),totalTargetAmount:e(y,g),effectiveRate:t,actionsWei:o}}return O.debug("getTradeDataFromActions info:",{sourceDecimals:n,targetDecimals:g,actionsWei:o,totalInput:f,totalOutput:p,tradingFeePPM:c,res:h}),h}async composeTradeByTargetTransaction(e,a,r,i,s,o){O.debug("composeTradeByTargetTransaction called",arguments);const c=await this._decimals.fetchDecimals(e);return this._api.composer.tradeByTargetAmount(e,a,r.map(k),i,t(s,c),o)}async composeTradeBySourceTransaction(e,a,r,i,s,o){O.debug("composeTradeBySourceTransaction called",arguments);const c=await this._decimals.fetchDecimals(a);return this._api.composer.tradeBySourceAmount(e,a,r.map(k),i,t(s,c),o)}async calculateOverlappingStrategySellBudget(e,t,a,r,i,s,o){O.debug("calculateOverlappingStrategySellBudget called",arguments);const c=this._decimals,d=await c.fetchDecimals(e),n=await c.fetchDecimals(t),g=b(d,n,a,r,i,s,o);return O.debug("calculateOverlappingStrategySellBudget info:",{baseDecimals:d,budget:g}),g}async calculateOverlappingStrategyBuyBudget(e,t,a,r,i,s,o){O.debug("calculateOverlappingStrategyBuyBudget called",arguments);const c=this._decimals,d=await c.fetchDecimals(e),n=await c.fetchDecimals(t),g=w(d,n,a,r,i,s,o);return O.debug("calculateOverlappingStrategyBuyBudget info:",{quoteDecimals:n,budget:g}),g}async createBuySellStrategy(e,t,a,r,i,s,o,c,d,n,g){O.debug("createBuySellStrategy called",arguments);const l=this._decimals,u=await l.fetchDecimals(e),m=await l.fetchDecimals(t),y=P(e,t,u,m,a,r,i,s,o,c,d,n),h=_(y);return O.debug("createBuySellStrategy info:",{strategy:y,encStrategy:h}),this._api.composer.createStrategy(h.token0,h.token1,h.order0,h.order1,g)}async batchCreateBuySellStrategies(e,t){O.debug("batchCreateBuySellStrategies called",arguments);const a=this._decimals,r=await Promise.all(e.map((async e=>{const t=await a.fetchDecimals(e.baseToken),r=await a.fetchDecimals(e.quoteToken),i=P(e.baseToken,e.quoteToken,t,r,e.buyPriceLow,e.buyPriceMarginal,e.buyPriceHigh,e.buyBudget,e.sellPriceLow,e.sellPriceMarginal,e.sellPriceHigh,e.sellBudget),s=_(i);return{token0:s.token0,token1:s.token1,order0:s.order0,order1:s.order1}})));return O.debug("batchCreateBuySellStrategies info:",{encStrategies:r}),this._api.composer.batchCreateStrategies(r,t)}async updateStrategy(e,t,{buyPriceLow:a,buyPriceHigh:r,buyBudget:o,sellPriceLow:c,sellPriceHigh:d,sellBudget:n},g,l,u){O.debug("updateStrategy called",arguments);const m=p(z(t)),y=await f(m,this._decimals),h=this._decimals,B=await h.fetchDecimals(y.baseToken),S=await h.fetchDecimals(y.quoteToken),b=P(y.baseToken,y.quoteToken,B,S,a??y.buyPriceLow,j(g)?g:r??y.buyPriceHigh,r??y.buyPriceHigh,o??y.buyBudget,c??y.sellPriceLow,j(l)?l:c??y.sellPriceLow,d??y.sellPriceHigh,n??y.sellBudget),w=_(b),D=z(t);return void 0===o&&void 0===a&&void 0===r&&void 0===g&&(w.order1.y=D.order1.y,w.order1.z=D.order1.z,w.order1.A=D.order1.A,w.order1.B=D.order1.B),void 0===n&&void 0===c&&void 0===d&&void 0===l&&(w.order0.y=D.order0.y,w.order0.z=D.order0.z,w.order0.A=D.order0.A,w.order0.B=D.order0.B),void 0===o&&(w.order1.y=D.order1.y),void 0===n&&(w.order0.y=D.order0.y),void 0===a&&void 0===r&&(w.order1.A=D.order1.A,w.order1.B=D.order1.B),void 0===c&&void 0===d&&(w.order0.A=D.order0.A,w.order0.B=D.order0.B),void 0!==o&&(j(g)||(g===R.maintain?D.order1.y.isZero()?w.order1.z=i(D.order1.z,w.order1.y):w.order1.z=s(D.order1.z,w.order1.y,D.order1.y):w.order1.z=w.order1.y)),void 0!==n&&(j(l)||(l===R.maintain?D.order0.y.isZero()?w.order0.z=i(D.order0.z,w.order0.y):w.order0.z=s(D.order0.z,w.order0.y,D.order0.y):w.order0.z=w.order0.y)),void 0===a&&void 0===r||g!==R.reset&&void 0!==g||(w.order1.z=w.order1.y),void 0===c&&void 0===d||l!==R.reset&&void 0!==l||(w.order0.z=w.order0.y),O.debug("updateStrategy info:",{baseDecimals:B,quoteDecimals:S,decodedOriginal:m,originalStrategy:y,newStrategy:b,newEncodedStrategy:w}),this._api.composer.updateStrategy(M.from(e),w.token0,w.token1,[D.order0,D.order1],[w.order0,w.order1],u)}async deleteStrategy(e){return O.debug("deleteStrategy called",arguments),this._api.composer.deleteStrategy(M.from(e))}async getRateLiquidityDepthsByPair(t,r,i){O.debug("getRateLiquidityDepthByPair called",arguments);const s=Object.values(await this._cache.getOrdersByPair(t,r)).map(v),o=this._decimals,c=await o.fetchDecimals(t),d=await o.fetchDecimals(r),n=i.map((e=>new a(D(e,d,c)))),g=l(s,n).map((e=>e.floor().toFixed(0))),u=g.map((t=>e(t,d)));return O.debug("getRateLiquidityDepthByPair info:",{orders:s,depthsWei:g,targetDecimals:d,depthsInTargetDecimals:u}),u}async getMinRateByPair(e,t){O.debug("getMinRateByPair called",arguments);const a=Object.values(await this._cache.getOrdersByPair(e,t)).map(v),r=u(a).toString(),i=this._decimals,s=await i.fetchDecimals(e),o=await i.fetchDecimals(t),c=D(r,s,o);return O.debug("getMinRateByPair info:",{orders:a,minRate:r,sourceDecimals:s,targetDecimals:o,normalizedRate:c}),c}async getMaxRateByPair(e,t){O.debug("getMaxRateByPair called",arguments);const a=Object.values(await this._cache.getOrdersByPair(e,t)).map(v),r=m(a).toString(),i=this._decimals,s=await i.fetchDecimals(e),o=await i.fetchDecimals(t),c=D(r,s,o);return O.debug("getMaxRateByPair info:",{orders:a,maxRate:r,sourceDecimals:s,targetDecimals:o,normalizedRate:c}),c}}export{R as MarginalPriceOptions,q as Toolkit,j as isMarginalPriceValue};