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