@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) • 18.1 kB
JavaScript
"use strict";var e=require("./numerics-WtCLBFmj.cjs"),t=require("./match-Bexumlk6.cjs"),r=require("./decimals-DbQULq1R.cjs"),a=require("./logger-d0ZZl9KP.cjs"),i=require("./encoders-DGguE7eh.cjs"),c=require("./serializers-DfRMJ_-P.cjs"),o=require("@ethersproject/bignumber");function s(t,r){const a=t.map((t=>{const r=new e.Decimal(t.lowestRate).sqrt(),a=new e.Decimal(t.marginalRate).sqrt();return{liq:new e.Decimal(t.liquidity),min:r,mid:a,midMinusMin:a.sub(r)}}));return r.map((t=>{const r=t.sqrt();return a.reduce(((t,a)=>t.add(function(t,r){if(r.lte(t.min))return t.liq;if(r.gte(t.mid))return new e.Decimal(0);return t.liq.sub(t.liq.mul(r.sub(t.min)).div(t.midMinusMin))}(a,r))),new e.Decimal(0))}))}const n=new a.Logger("utils.ts");function d(t,r,a){return new e.Decimal(t.toString()).times(e.tenPow(r,a)).toFixed()}function l(t,r,a){return 0==+t.toString()?"0":new e.Decimal(1).div(t.toString()).times(e.tenPow(a,r)).toFixed()}const g=e=>{const[t,r]=i.encodeOrders([e.order0,e.order1]);return{token0:e.token0,token1:e.token1,order0:t,order1:r}},u=e=>({id:e.id,token0:e.token0,token1:e.token1,order0:i.decodeOrder(e.order0),order1:i.decodeOrder(e.order1),encoded:e});async function m(t,r){n.debug("parseStrategy called",arguments);const{id:a,token0:i,token1:o,order0:s,order1:g,encoded:u}=t,m=await r.fetchDecimals(i),y=await r.fetchDecimals(o),h=d(g.lowestRate,m,y),p=d(g.marginalRate,m,y),w=d(g.highestRate,m,y),b=l(s.highestRate,y,m),f=l(s.marginalRate,y,m),B=l(s.lowestRate,y,m),S=e.formatUnits(s.liquidity,m),P=e.formatUnits(g.liquidity,y),D=a.toString(),v=c.encodedStrategyBNToStr(u);return n.debug("parseStrategy info:",{id:D,token0:i,token1:o,order0:s,order1:g,decimals0:m,decimals1:y,baseToken:i,quoteToken:o,buyPriceLow:h,buyPriceMarginal:p,buyPriceHigh:w,buyBudget:P,sellPriceLow:b,sellPriceMarginal:f,sellPriceHigh:B,sellBudget:S,encoded:v}),{id:D,baseToken:i,quoteToken:o,buyPriceLow:h,buyPriceMarginal:p,buyPriceHigh:w,buyBudget:P,sellPriceLow:b,sellPriceMarginal:f,sellPriceHigh:B,sellBudget:S,encoded:v}}function y(t,r,a,i,c,o,s,d,l,g,u,m){if(n.debug("buildStrategyObject called",arguments),new e.Decimal(c).isNegative()||new e.Decimal(o).isNegative()||new e.Decimal(s).isNegative()||new e.Decimal(l).isNegative()||new e.Decimal(g).isNegative()||new e.Decimal(u).isNegative())throw new Error("prices cannot be negative");if(new e.Decimal(c).gt(o)||new e.Decimal(c).gt(s)||new e.Decimal(o).gt(s)||new e.Decimal(l).gt(g)||new e.Decimal(l).gt(u)||new e.Decimal(g).gt(u))throw new Error("low/marginal price must be lower than or equal to marginal/high price");if(new e.Decimal(d).isNegative()||new e.Decimal(m).isNegative())throw new Error("budgets cannot be negative");const{order0:y,order1:h}=w(a,i,c,o,s,d,l,g,u,m);return n.debug("buildStrategyObject info:",{token0:t,token1:r,order0:y,order1:h}),{token0:t,token1:r,order0:y,order1:h}}function h(t,r,a,i,c,o){n.debug("createFromBuyOrder called",arguments);const s=e.parseUnits(o,r),l=d(a,r,t),g=d(i,r,t),u=d(c,r,t),m={liquidity:s.toString(),lowestRate:l,highestRate:u,marginalRate:g};return n.debug("createFromBuyOrder info:",{order:m}),m}function p(t,r,a,i,c,o){n.debug("createFromSellOrder called",arguments);const s=e.parseUnits(o,t),d=l(c,r,t),g=l(i,r,t),u=l(a,r,t),m={liquidity:s.toString(),lowestRate:d,highestRate:u,marginalRate:g};return n.debug("createFromSellOrder info:",{order:m}),m}function w(e,t,r,a,i,c,o,s,d,l){n.debug("createOrders called",arguments);const g=p(e,t,o,s,d,l),u=h(e,t,r,a,i,c);return n.debug("createOrders info:",{order0:g,order1:u}),{order0:g,order1:u}}const b=1e6;function f(t,r){return new e.Decimal(t.toString()).mul(b).div(b-r).ceil()}function B(t,r){return new e.Decimal(t.toString()).mul(b-r).div(b).floor()}function S(e,t,r){return r.lte(e)?e:r.gte(t)?t:r}function P(e,t){return{minBuyPrice:d(i.lowestPossibleRate.toString(),e,t),maxSellPrice:l(i.lowestPossibleRate.toString(),t,e)}}function D(t,r,a,i){n.debug("calculateOverlappingPrices called",arguments);const c=new e.Decimal(i).div(100).plus(1),o=new e.Decimal(r).div(c),s=new e.Decimal(t).mul(c),d=S(new e.Decimal(t),o,new e.Decimal(a).div(c.sqrt())),l=S(s,new e.Decimal(r),new e.Decimal(a).mul(c.sqrt())),g={buyPriceHigh:o.toString(),buyPriceMarginal:d.toString(),sellPriceLow:s.toString(),sellPriceMarginal:l.toString(),buyPriceLow:t,sellPriceHigh:r,marketPrice:a};return n.debug("calculateOverlappingPrices info:",{prices:g}),g}function v(t,r,a,c,o,s,d){if(n.debug("calculateOverlappingSellBudget called",arguments),"0"===d)return"0";const{buyPriceHigh:l,sellPriceLow:g,sellPriceMarginal:u,buyPriceMarginal:m}=D(a,c,o,s);if(new e.Decimal(u).gte(c))return"0";if(new e.Decimal(m).lte(a))throw new Error("calculateOverlappingSellBudget called with zero buy range and non zero buy budget");const y=h(t,r,a,m,l,d),w=p(t,r,g,u,c,"0"),b=i.calculateRequiredLiquidity(y,w),f=e.formatUnits(b,t);return n.debug("calculateOverlappingSellBudget info:",{sellBudget:f}),f}function O(t,r,a,c,o,s,d){if(n.debug("calculateOverlappingBuyBudget called",arguments),"0"===d)return"0";const{sellPriceLow:l,buyPriceHigh:g,sellPriceMarginal:u,buyPriceMarginal:m}=D(a,c,o,s);if(new e.Decimal(m).lte(a))return"0";if(new e.Decimal(u).gte(c))throw new Error("calculateOverlappingBuyBudget called with zero sell range and non zero sell budget");const y=h(t,r,a,m,g,"0"),w=p(t,r,l,u,c,d),b=i.calculateRequiredLiquidity(w,y),f=e.formatUnits(b,r);return n.debug("calculateOverlappingBuyBudget info:",{buyBudget:f}),f}const _=new a.Logger("Toolkit.ts");var M;function T(e){return void 0!==e&&e!==exports.MarginalPriceOptions.reset&&e!==exports.MarginalPriceOptions.maintain}exports.MarginalPriceOptions=void 0,(M=exports.MarginalPriceOptions||(exports.MarginalPriceOptions={})).reset="RESET",M.maintain="MAINTAIN";class x{_api;_decimals;_cache;constructor(e,t,a){_.debug("SDK class constructor called with",arguments),this._api=e,this._cache=t;this._decimals=new r.Decimals((async e=>await(a?.(e))??await this._api.reader.getDecimalsByAddress(e)))}async getMinMaxPricesByAddresses(e,t){const r=this._decimals;return P(await r.fetchDecimals(e),await r.fetchDecimals(t))}static getMatchActions(e,r,a,i=t.MatchType.Fast,s){const n=c.ordersMapStrToBN(a);let d;return d=r?t.matchByTargetAmount(o.BigNumber.from(e),n,[i],s):t.matchBySourceAmount(o.BigNumber.from(e),n,[i],s),d[i]?.map(c.matchActionBNToStr)??[]}async hasLiquidityByPair(e,t){_.debug("hasLiquidityByPair called",arguments);const r=await this._cache.getOrdersByPair(e,t);return _.debug("hasLiquidityByPair info:",{orders:r}),Object.keys(r).length>0}async getLiquidityByPair(t,r){_.debug("getLiquidityByPair called",arguments);const a=await this._cache.getOrdersByPair(t,r),i=Object.values(a).reduce(((e,{y:t})=>e.add(t)),o.BigNumber.from(0)),c=await this._decimals.fetchDecimals(r),s=e.formatUnits(i,c);return _.debug("getLiquidityByPair info:",{orders:a,liquidityWei:i,targetToken:r,decimals:c,liquidity:s}),s}async getMaxSourceAmountByPair(r,a){_.debug("getMaxSourceAmountByPair called",arguments);const i=await this._cache.getOrdersByPair(r,a),c=Object.values(i).reduce(((e,r)=>e.add(t.getEncodedTradeSourceAmount(r.y,r))),o.BigNumber.from(0)),s=await this._decimals.fetchDecimals(r),n=e.formatUnits(c,s);return _.debug("getMaxSourceAmountByPair info:",{orders:i,maxSourceAmountWei:c,sourceToken:r,decimals:s,maxSourceAmount:n}),n}async getStrategyById(e){let t;_.debug("getStrategyById called",arguments),this._cache.isCacheInitialized()&&(t=this._cache.getStrategyById(e)),t?_.debug("getStrategyById fetched from cache"):(_.debug("getStrategyById fetching from chain"),t=await this._api.reader.strategy(o.BigNumber.from(e)));const r=u(t),a=await m(r,this._decimals);return _.debug("getStrategyById info:",{id:e,encodedStrategy:t,decodedStrategy:r,strategy:a}),a}async getStrategiesByPair(e,t){let r;_.debug("getStrategiesByPair called",arguments),this._cache.isCacheInitialized()&&(r=await this._cache.getStrategiesByPair(e,t)),r?_.debug("getStrategiesByPair fetched from cache"):(_.debug("getStrategiesByPair fetching from chain"),r=await this._api.reader.strategiesByPair(e,t));const a=r.map(u),i=await Promise.all(a.map((async e=>await m(e,this._decimals))));return _.debug("getStrategiesByPair info:",{token0:e,token1:t,encodedStrategies:r,decodedStrategies:a,strategies:i}),i}async getStrategiesByPairs(e){_.debug("getStrategiesByPairs called",arguments);let t,r=e;r||(r=this._cache.isCacheInitialized()?this._cache.getCachedPairs():await this._api.reader.pairs()),this._cache.isCacheInitialized()?(t=await this._cache.getStrategiesByPairs(r),_.debug("getStrategiesByPairs fetched from cache")):(_.debug("getStrategiesByPairs fetching from chain"),t=await this._api.reader.strategiesByPairs(r));const a=t.map((({pair:e,strategies:t})=>({pair:e,strategies:t.map(u)}))),i=await Promise.all(a.map((async({pair:e,strategies:t})=>({pair:e,strategies:await Promise.all(t.map((async e=>await m(e,this._decimals))))}))));return _.debug("getStrategiesByPairs info:",{pairs:e,pairsToFetch:r,encodedStrategies:t,decodedStrategies:a,strategies:i}),i}async getUserStrategies(e){_.debug("getUserStrategies called",arguments);const t=await this._api.reader.tokensByOwner(e);let r=[],a=t;if(this._cache.isCacheInitialized()&&(a=t.reduce(((e,t)=>{const a=this._cache.getStrategyById(t);return a?r.push(a):e.push(t),e}),[])),a.length>0){const e=await this._api.reader.strategies(a);r=[...r,...e]}const i=r.map(u),c=await Promise.all(i.map((async e=>await m(e,this._decimals))));return _.debug("getUserStrategies info:",{ids:t,encodedStrategies:r,decodedStrategies:i,strategies:c}),c}async getMatchParams(t,r,a,i){_.debug("getMatchParams called",arguments);const o=this._decimals,s=await o.fetchDecimals(t),n=await o.fetchDecimals(r),d=await this._cache.getOrdersByPair(t,r),l=e.parseUnits(a,i?n:s);return{orders:c.ordersMapBNToStr(d),amountWei:l.toString(),sourceDecimals:s,targetDecimals:n}}async getTradeData(e,r,a,i,c=t.MatchType.Fast,o){_.debug("getTradeData called",arguments);const{orders:s,amountWei:n}=await this.getMatchParams(e,r,a,i),d=x.getMatchActions(n,i,s,c,o),l=await this.getTradeDataFromActions(e,r,i,d);return _.debug("getTradeData info:",{orders:s,amount:a,amountWei:n,res:l}),l}async getTradeDataFromActions(t,r,a,i){_.debug("getTradeDataFromActions called",arguments);const c=await this._cache.getTradingFeePPMByPair(t,r);if(void 0===c)throw new Error(`tradingFeePPM is undefined for this pair: ${t}-${r}`);const s=this._decimals,n=await s.fetchDecimals(t),d=await s.fetchDecimals(r),l=[],g=[];let u,m,y,h=o.BigNumber.from(0),p=o.BigNumber.from(0);if(i.forEach((t=>{l.push({strategyId:t.id,amount:t.input}),a?g.push({id:t.id,sourceAmount:e.formatUnits(f(t.output,c).floor().toFixed(0),n),targetAmount:e.formatUnits(t.input,d)}):g.push({id:t.id,sourceAmount:e.formatUnits(t.input,n),targetAmount:e.formatUnits(B(t.output,c).floor().toFixed(0),d)}),p=p.add(t.input),h=h.add(t.output)})),a?(u=f(h,c).floor().toFixed(0),m=p.toString()):(u=p.toString(),m=B(h,c).floor().toFixed(0)),new e.Decimal(u).isZero()||new e.Decimal(m).isZero())y={tradeActions:l,actionsTokenRes:g,totalSourceAmount:"0",totalTargetAmount:"0",effectiveRate:"0",actionsWei:i};else{const t=new e.Decimal(m).div(u).times(e.tenPow(n,d)).toString();y={tradeActions:l,actionsTokenRes:g,totalSourceAmount:e.formatUnits(u,n),totalTargetAmount:e.formatUnits(m,d),effectiveRate:t,actionsWei:i}}return _.debug("getTradeDataFromActions info:",{sourceDecimals:n,targetDecimals:d,actionsWei:i,totalInput:p,totalOutput:h,tradingFeePPM:c,res:y}),y}async composeTradeByTargetTransaction(t,r,a,i,o,s){_.debug("composeTradeByTargetTransaction called",arguments);const n=await this._decimals.fetchDecimals(t);return this._api.composer.tradeByTargetAmount(t,r,a.map(c.tradeActionStrToBN),i,e.parseUnits(o,n),s)}async composeTradeBySourceTransaction(t,r,a,i,o,s){_.debug("composeTradeBySourceTransaction called",arguments);const n=await this._decimals.fetchDecimals(r);return this._api.composer.tradeBySourceAmount(t,r,a.map(c.tradeActionStrToBN),i,e.parseUnits(o,n),s)}async calculateOverlappingStrategySellBudget(e,t,r,a,i,c,o){_.debug("calculateOverlappingStrategySellBudget called",arguments);const s=this._decimals,n=await s.fetchDecimals(e),d=v(n,await s.fetchDecimals(t),r,a,i,c,o);return _.debug("calculateOverlappingStrategySellBudget info:",{baseDecimals:n,budget:d}),d}async calculateOverlappingStrategyBuyBudget(e,t,r,a,i,c,o){_.debug("calculateOverlappingStrategyBuyBudget called",arguments);const s=this._decimals,n=await s.fetchDecimals(e),d=await s.fetchDecimals(t),l=O(n,d,r,a,i,c,o);return _.debug("calculateOverlappingStrategyBuyBudget info:",{quoteDecimals:d,budget:l}),l}async createBuySellStrategy(e,t,r,a,i,c,o,s,n,d,l){_.debug("createBuySellStrategy called",arguments);const u=this._decimals,m=y(e,t,await u.fetchDecimals(e),await u.fetchDecimals(t),r,a,i,c,o,s,n,d),h=g(m);return _.debug("createBuySellStrategy info:",{strategy:m,encStrategy:h}),this._api.composer.createStrategy(h.token0,h.token1,h.order0,h.order1,l)}async batchCreateBuySellStrategies(e,t){_.debug("batchCreateBuySellStrategies called",arguments);const r=this._decimals,a=await Promise.all(e.map((async e=>{const t=await r.fetchDecimals(e.baseToken),a=await r.fetchDecimals(e.quoteToken),i=y(e.baseToken,e.quoteToken,t,a,e.buyPriceLow,e.buyPriceMarginal,e.buyPriceHigh,e.buyBudget,e.sellPriceLow,e.sellPriceMarginal,e.sellPriceHigh,e.sellBudget),c=g(i);return{token0:c.token0,token1:c.token1,order0:c.order0,order1:c.order1}})));return _.debug("batchCreateBuySellStrategies info:",{encStrategies:a}),this._api.composer.batchCreateStrategies(a,t)}async updateStrategy(t,r,{buyPriceLow:a,buyPriceHigh:i,buyBudget:s,sellPriceLow:n,sellPriceHigh:d,sellBudget:l},h,p,w){_.debug("updateStrategy called",arguments);const b=u(c.encodedStrategyStrToBN(r)),f=await m(b,this._decimals),B=this._decimals,S=await B.fetchDecimals(f.baseToken),P=await B.fetchDecimals(f.quoteToken),D=y(f.baseToken,f.quoteToken,S,P,a??f.buyPriceLow,T(h)?h:i??f.buyPriceHigh,i??f.buyPriceHigh,s??f.buyBudget,n??f.sellPriceLow,T(p)?p:n??f.sellPriceLow,d??f.sellPriceHigh,l??f.sellBudget),v=g(D),O=c.encodedStrategyStrToBN(r);return void 0===s&&void 0===a&&void 0===i&&void 0===h&&(v.order1.y=O.order1.y,v.order1.z=O.order1.z,v.order1.A=O.order1.A,v.order1.B=O.order1.B),void 0===l&&void 0===n&&void 0===d&&void 0===p&&(v.order0.y=O.order0.y,v.order0.z=O.order0.z,v.order0.A=O.order0.A,v.order0.B=O.order0.B),void 0===s&&(v.order1.y=O.order1.y),void 0===l&&(v.order0.y=O.order0.y),void 0===a&&void 0===i&&(v.order1.A=O.order1.A,v.order1.B=O.order1.B),void 0===n&&void 0===d&&(v.order0.A=O.order0.A,v.order0.B=O.order0.B),void 0!==s&&(T(h)||(h===exports.MarginalPriceOptions.maintain?O.order1.y.isZero()?v.order1.z=e.BigNumberMax(O.order1.z,v.order1.y):v.order1.z=e.mulDiv(O.order1.z,v.order1.y,O.order1.y):v.order1.z=v.order1.y)),void 0!==l&&(T(p)||(p===exports.MarginalPriceOptions.maintain?O.order0.y.isZero()?v.order0.z=e.BigNumberMax(O.order0.z,v.order0.y):v.order0.z=e.mulDiv(O.order0.z,v.order0.y,O.order0.y):v.order0.z=v.order0.y)),void 0===a&&void 0===i||h!==exports.MarginalPriceOptions.reset&&void 0!==h||(v.order1.z=v.order1.y),void 0===n&&void 0===d||p!==exports.MarginalPriceOptions.reset&&void 0!==p||(v.order0.z=v.order0.y),_.debug("updateStrategy info:",{baseDecimals:S,quoteDecimals:P,decodedOriginal:b,originalStrategy:f,newStrategy:D,newEncodedStrategy:v}),this._api.composer.updateStrategy(o.BigNumber.from(t),v.token0,v.token1,[O.order0,O.order1],[v.order0,v.order1],w)}async deleteStrategy(e){return _.debug("deleteStrategy called",arguments),this._api.composer.deleteStrategy(o.BigNumber.from(e))}async getRateLiquidityDepthsByPair(t,r,a){_.debug("getRateLiquidityDepthByPair called",arguments);const c=Object.values(await this._cache.getOrdersByPair(t,r)).map(i.decodeOrder),o=this._decimals,n=await o.fetchDecimals(t),l=await o.fetchDecimals(r),g=s(c,a.map((t=>new e.Decimal(d(t,l,n))))).map((e=>e.floor().toFixed(0))),u=g.map((t=>e.formatUnits(t,l)));return _.debug("getRateLiquidityDepthByPair info:",{orders:c,depthsWei:g,targetDecimals:l,depthsInTargetDecimals:u}),u}async getMinRateByPair(t,r){_.debug("getMinRateByPair called",arguments);const a=Object.values(await this._cache.getOrdersByPair(t,r)).map(i.decodeOrder),c=function(t){return t.reduce(((t,r)=>e.Decimal.min(t,r.lowestRate)),new e.Decimal(1/0))}(a).toString(),o=this._decimals,s=await o.fetchDecimals(t),n=await o.fetchDecimals(r),l=d(c,s,n);return _.debug("getMinRateByPair info:",{orders:a,minRate:c,sourceDecimals:s,targetDecimals:n,normalizedRate:l}),l}async getMaxRateByPair(t,r){_.debug("getMaxRateByPair called",arguments);const a=Object.values(await this._cache.getOrdersByPair(t,r)).map(i.decodeOrder),c=function(t){return t.reduce(((t,r)=>e.Decimal.max(t,r.marginalRate)),new e.Decimal(-1/0))}(a).toString(),o=this._decimals,s=await o.fetchDecimals(t),n=await o.fetchDecimals(r),l=d(c,s,n);return _.debug("getMaxRateByPair info:",{orders:a,maxRate:c,sourceDecimals:s,targetDecimals:n,normalizedRate:l}),l}}var k=Object.freeze({__proto__:null,get MarginalPriceOptions(){return exports.MarginalPriceOptions},PPM_RESOLUTION:b,Toolkit:x,addFee:f,buildStrategyObject:y,calculateOverlappingBuyBudget:O,calculateOverlappingPrices:D,calculateOverlappingSellBudget:v,createFromBuyOrder:h,createFromSellOrder:p,createOrders:w,decodeStrategy:u,encodeStrategy:g,enforcePriceRange:S,getMinMaxPricesByDecimals:P,isMarginalPriceValue:T,normalizeInvertedRate:l,normalizeRate:d,parseStrategy:m,subtractFee:B});exports.PPM_RESOLUTION=b,exports.Toolkit=x,exports.addFee=f,exports.buildStrategyObject=y,exports.calculateOverlappingBuyBudget=O,exports.calculateOverlappingPrices=D,exports.calculateOverlappingSellBudget=v,exports.createFromBuyOrder=h,exports.createFromSellOrder=p,exports.createOrders=w,exports.decodeStrategy=u,exports.encodeStrategy=g,exports.enforcePriceRange=S,exports.getMinMaxPricesByDecimals=P,exports.index=k,exports.isMarginalPriceValue=T,exports.normalizeInvertedRate=l,exports.normalizeRate=d,exports.parseStrategy=m,exports.subtractFee=B;