Socket
Socket
Sign inDemoInstall

@sora-substrate/liquidity-proxy

Package Overview
Dependencies
1
Maintainers
1
Versions
326
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.35.6 to 1.35.7

15

build/consts.d.ts

@@ -24,2 +24,6 @@ import { FPNumber } from '@sora-substrate/math';

static readonly MAX: FPNumber;
/** Manimal significant balance */
static readonly MIN: FPNumber;
/** Irreducible reserve percent = 1% */
static readonly IrreducibleReserve: FPNumber;
/** ETH & DAI which are incentivized */

@@ -32,7 +36,11 @@ static readonly incentivizedCurrenciesNum: FPNumber;

export declare enum Errors {
PriceCalculationFailed = "An error occurred while calculating the price.",
CalculationError = "Specified parameters lead to arithmetic error",
CantExchange = "Liquidity source can't exchange assets with the given IDs on the given DEXId.",
PoolIsEmpty = "The pool has empty liquidity.",
InsufficientLiquidity = "None of the sources has enough reserves to execute a trade",
InvalidOrderAmount = "Invalid Order Amount",
InvalidFeeRatio = "Invalid fee ratio value.",
NotEnoughLiquidityInOrderBook = "Not Enough Liquidity In OrderBook",
NotEnoughReserves = "It's not enough reserves in the pool to perform the operation.",
PoolIsEmpty = "The pool has empty liquidity.",
PriceCalculationFailed = "An error occurred while calculating the price.",
SyntheticDoesNotExist = "Synthetic asset does not exist.",

@@ -42,4 +50,3 @@ SyntheticBaseBuySellLimitExceeded = "Input/output amount of synthetic base asset exceeds the limit",

UnknownOrderBook = "Order book does not exist for this trading pair",
NotEnoughLiquidityInOrderBook = "Not Enough Liquidity In OrderBook",
InvalidOrderAmount = "Invalid Order Amount",
UnsupportedQuotePath = "Attempt to quote via unsupported path, i.e. both output and input tokens are not XOR.",
UnsupportedLiquiditySource = "Unsupported liquidity source"

@@ -46,0 +53,0 @@ }

@@ -21,2 +21,4 @@ "use strict";

Consts.MAX = new _math.FPNumber('170141183460469231731.687303715884105727');
Consts.MIN = _math.FPNumber.fromCodecValue(1);
Consts.IrreducibleReserve = new _math.FPNumber(0.01);
Consts.incentivizedCurrenciesNum = _math.FPNumber.TWO;

@@ -28,7 +30,11 @@ Consts.initialPswapTbcRewardsAmount = new _math.FPNumber(2500000000);

(function (Errors) {
Errors["PriceCalculationFailed"] = "An error occurred while calculating the price.";
Errors["CalculationError"] = "Specified parameters lead to arithmetic error";
Errors["CantExchange"] = "Liquidity source can't exchange assets with the given IDs on the given DEXId.";
Errors["PoolIsEmpty"] = "The pool has empty liquidity.";
Errors["InsufficientLiquidity"] = "None of the sources has enough reserves to execute a trade";
Errors["InvalidOrderAmount"] = "Invalid Order Amount";
Errors["InvalidFeeRatio"] = "Invalid fee ratio value.";
Errors["NotEnoughLiquidityInOrderBook"] = "Not Enough Liquidity In OrderBook";
Errors["NotEnoughReserves"] = "It's not enough reserves in the pool to perform the operation.";
Errors["PoolIsEmpty"] = "The pool has empty liquidity.";
Errors["PriceCalculationFailed"] = "An error occurred while calculating the price.";
Errors["SyntheticDoesNotExist"] = "Synthetic asset does not exist.";

@@ -38,4 +44,3 @@ Errors["SyntheticBaseBuySellLimitExceeded"] = "Input/output amount of synthetic base asset exceeds the limit";

Errors["UnknownOrderBook"] = "Order book does not exist for this trading pair";
Errors["NotEnoughLiquidityInOrderBook"] = "Not Enough Liquidity In OrderBook";
Errors["InvalidOrderAmount"] = "Invalid Order Amount";
Errors["UnsupportedQuotePath"] = "Attempt to quote via unsupported path, i.e. both output and input tokens are not XOR.";
Errors["UnsupportedLiquiditySource"] = "Unsupported liquidity source";

@@ -42,0 +47,0 @@ })(Errors || (exports.Errors = Errors = {}));

{
"name": "@sora-substrate/liquidity-proxy",
"version": "1.35.6",
"version": "1.35.7",
"license": "Apache-2.0",

@@ -11,4 +11,4 @@ "main": "./build/index.js",

"dependencies": {
"@sora-substrate/math": "1.35.6"
"@sora-substrate/math": "1.35.7"
}
}

@@ -18,3 +18,3 @@ import { FPNumber } from '@sora-substrate/math';

addSource(source: LiquiditySourceTypes, discreteQuotation: DiscreteQuotation): void;
aggregateSwapOutcome(amount: FPNumber): AggregatedSwapOutcome | null;
aggregateSwapOutcome(amount: FPNumber): AggregatedSwapOutcome;
findBestPriceCandidates(locked?: LiquiditySourceTypes[]): Array<LiquiditySourceTypes>;

@@ -21,0 +21,0 @@ sumChunks(chunks: SwapChunk[]): SwapChunk;

@@ -25,3 +25,3 @@ "use strict";

aggregateSwapOutcome(amount) {
if (!this.liquidityQuotations.size) return null;
if (!this.liquidityQuotations.size) throw new Error(_consts.Errors.InsufficientLiquidity);
let remainingAmount = amount;

@@ -34,3 +34,3 @@ const lockedSources = [];

let source = candidates[0];
if (!source) return null;
if (!source) throw new Error(_consts.Errors.InsufficientLiquidity);

@@ -46,5 +46,5 @@ // if there are several candidates with the same best price,

const discreteQuotation = this.liquidityQuotations.get(source);
if (!discreteQuotation) return null;
if (!discreteQuotation) throw new Error(_consts.Errors.InsufficientLiquidity);
let chunk = discreteQuotation.chunks.shift();
if (!chunk) return null;
if (!chunk) throw new Error(_consts.Errors.InsufficientLiquidity);
let payback = _primitives.SwapChunk.zero();

@@ -78,3 +78,3 @@ const total = this.sumChunks((_selected$get = selected.get(source)) !== null && _selected$get !== void 0 ? _selected$get : []);

const remainingSubResult = (0, _utils.checkedSub)(remainingAmount, remainingDelta);
if (!remainingSubResult) return null;
if (!remainingSubResult) throw new Error(_consts.Errors.CalculationError);
remainingAmount = remainingSubResult;

@@ -86,3 +86,3 @@ if (remainingAmount.isZero()) {

const discreteQuotation = this.liquidityQuotations.get(source);
if (!discreteQuotation) return null;
if (!discreteQuotation) throw new Error(_consts.Errors.InsufficientLiquidity);
const [aligned, remainder] = discreteQuotation.limits.alignChunk(total);

@@ -110,3 +110,3 @@ if (!remainder.isZero()) {

const value = (0, _utils.checkedSub)(remainderSide.amount, chunk.getAssociatedField(this.variant).amount);
if (!value) return null;
if (!value) throw new Error(_consts.Errors.CalculationError);
remainderSide.amount = value;

@@ -113,0 +113,0 @@ discreteQuotation.chunks.unshift(chunk);

@@ -193,5 +193,2 @@ "use strict";

const result = aggregator.aggregateSwapOutcome(amount);
if (!result) {
throw new Error(_consts.Errors.UnavailableExchangePath);
}
const rewards = [];

@@ -198,0 +195,0 @@ for (const {

@@ -34,2 +34,20 @@ "use strict";

}
// reduce amount if it exceeds reserves
if ((0, _utils.isAssetAddress)(inputAsset, baseAssetId)) {
const collateralSupply = (0, _utils.toFp)(payload.reserves.tbc[outputAsset]);
if (collateralSupply.isZero()) return quotation;
const [adjustedAmount, maxLimit] = (() => {
if (!isDesiredInput) {
// reduce by `IrreducibleReserve` percent, because (reserve - output) must be > 0
const maxValue = (0, _utils.saturatingSub)(collateralSupply, _consts.Consts.IrreducibleReserve.mul(collateralSupply));
const value = maxValue.min(amount);
return [value, new _primitives.SideAmount(maxValue, _consts.SwapVariant.WithDesiredOutput)];
} else {
return [amount, null];
}
})();
quotation.limits.maxAmount = maxLimit;
amount = adjustedAmount;
}
const samplesCount = recommendedSamplesCount < 1 ? 1 : recommendedSamplesCount;

@@ -61,13 +79,2 @@ const step = (0, _utils.safeDivide)(amount, new _math.FPNumber(samplesCount));

}
if ((0, _utils.isAssetAddress)(inputAsset, baseAssetId)) {
const collateralSupply = (0, _utils.toFp)(payload.reserves.tbc[outputAsset]);
if (isDesiredInput) {
const mainPricePerReferenceUnit = sellFunction(inputAsset, outputAsset, _math.FPNumber.ZERO, payload);
const collateralPricePerReferenceUnit = referencePrice(outputAsset, _consts.PriceVariant.Sell, payload);
const mainSupply = (0, _utils.safeDivide)(collateralSupply.mul(collateralPricePerReferenceUnit), mainPricePerReferenceUnit);
quotation.limits.maxAmount = new _primitives.SideAmount(mainSupply, _consts.SwapVariant.WithDesiredInput);
} else {
quotation.limits.maxAmount = new _primitives.SideAmount(collateralSupply, _consts.SwapVariant.WithDesiredOutput);
}
}
return quotation;

@@ -74,0 +81,0 @@ };

@@ -20,4 +20,24 @@ "use strict";

// decide_is_fee_from_destination
exports.canExchange = canExchange;
const decideIsFeeFromDestination = (baseAssetId, assetA, assetB) => {
if ((0, _utils.isAssetAddress)(baseAssetId, assetA)) {
return false;
} else if ((0, _utils.isAssetAddress)(baseAssetId, assetB)) {
return true;
} else {
throw new Error(_consts.Errors.UnavailableExchangePath);
}
};
// calc_max_output
const calcMaxOutput = (getFeeFromDestination, reserveOutput, deduceFee) => {
if (reserveOutput.isZero()) return _math.FPNumber.ZERO;
const maxOutput = getFeeFromDestination && deduceFee ? reserveOutput.mul(_math.FPNumber.ONE.sub(_consts.Consts.XYK_FEE)) : reserveOutput;
// // reduce by `IrreducibleReserve` percent, because (reserve - output) must be > 0
return (0, _utils.saturatingSub)(maxOutput, _consts.Consts.IrreducibleReserve.mul(maxOutput));
};
// step_quote
exports.canExchange = canExchange;
const stepQuote = (baseAssetId, _syntheticBaseAssetId, inputAsset, outputAsset, amount, isDesiredInput, payload, deduceFee, recommendedSamplesCount) => {

@@ -35,4 +55,14 @@ const quotation = new _primitives.DiscreteQuotation();

if (_math.FPNumber.isLessThanOrEqualTo(reserveInput, _math.FPNumber.ZERO) || _math.FPNumber.isLessThanOrEqualTo(reserveOutput, _math.FPNumber.ZERO)) {
throw new Error(_consts.Errors.PoolIsEmpty);
return quotation;
}
const getFeeFromDestination = decideIsFeeFromDestination(baseAssetId, inputAsset, outputAsset);
amount = (() => {
if (isDesiredInput) {
return amount;
} else {
const maxOutput = calcMaxOutput(getFeeFromDestination, reserveOutput, deduceFee);
quotation.limits.maxAmount = new _primitives.SideAmount(maxOutput, _consts.SwapVariant.WithDesiredOutput);
return maxOutput.min(amount);
}
})();
const commonStep = (0, _utils.safeDivide)(amount, new _math.FPNumber(samplesCount));

@@ -45,3 +75,3 @@ // volume & step

volumes.push([volume, commonStep]);
remaining = remaining.sub(commonStep);
remaining = (0, _utils.saturatingSub)(remaining, commonStep);
}

@@ -56,5 +86,5 @@ volumes.push([amount, remaining]);

fee
} = calcOutputForExactInput(baseAssetId, inputAsset, outputAsset, reserveInput, reserveOutput, volume, deduceFee);
const output = calculated.sub(subSum);
const feeChunk = fee.sub(subFee);
} = calcOutputForExactInput(getFeeFromDestination, inputAsset, outputAsset, reserveInput, reserveOutput, volume, deduceFee);
const output = (0, _utils.saturatingSub)(calculated, subSum);
const feeChunk = (0, _utils.saturatingSub)(fee, subFee);
subSum = calculated;

@@ -69,5 +99,5 @@ subFee = fee;

fee
} = calcInputForExactOutput(baseAssetId, inputAsset, outputAsset, reserveInput, reserveOutput, volume, deduceFee);
const input = calculated.sub(subSum);
const feeChunk = fee.sub(subFee);
} = calcInputForExactOutput(getFeeFromDestination, inputAsset, outputAsset, reserveInput, reserveOutput, volume, deduceFee);
const input = (0, _utils.saturatingSub)(calculated, subSum);
const feeChunk = (0, _utils.saturatingSub)(fee, subFee);
subSum = calculated;

@@ -162,3 +192,3 @@ subFee = fee;

}
const fxwYout = yOut.add(_math.FPNumber.fromCodecValue(1)); // by 1 correction to overestimate required input
const fxwYout = yOut.add(_consts.Consts.MIN); // by 1 correction to overestimate required input
const nominator = x.mul(fxwYout);

@@ -192,3 +222,3 @@ const denominator = y.sub(fxwYout);

const xykQuoteD = (input, output, x, y, yOut, deduceFee) => {
const fxwYout = yOut.add(_math.FPNumber.fromCodecValue(1)); // by 1 correction to overestimate required input
const fxwYout = yOut.add(_consts.Consts.MIN); // by 1 correction to overestimate required input
const yOutWithFee = deduceFee ? (0, _utils.safeDivide)(fxwYout, _math.FPNumber.ONE.sub(_consts.Consts.XYK_FEE)) : fxwYout;

@@ -218,9 +248,17 @@ if (_math.FPNumber.isGreaterThanOrEqualTo(yOutWithFee, y)) {

// calc_output_for_exact_input
const calcOutputForExactInput = (baseAssetId, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee) => {
return (0, _utils.isAssetAddress)(inputAsset, baseAssetId) ? xykQuoteA(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee) : xykQuoteB(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
const calcOutputForExactInput = (getFeeFromDestination, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee) => {
if (getFeeFromDestination) {
return xykQuoteB(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
} else {
return xykQuoteA(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
}
};
// calc_input_for_exact_output
const calcInputForExactOutput = (baseAssetId, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee) => {
return (0, _utils.isAssetAddress)(inputAsset, baseAssetId) ? xykQuoteC(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee) : xykQuoteD(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
const calcInputForExactOutput = (getFeeFromDestination, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee) => {
if (getFeeFromDestination) {
return xykQuoteD(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
} else {
return xykQuoteC(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
}
};

@@ -233,3 +271,4 @@ const quote = (baseAssetId, _syntheticBaseAssetId, inputAsset, outputAsset, amount, isDesiredInput, payload, deduceFee) => {

const [inputReserves, outputReserves] = getXykReserves(inputAsset, outputAsset, payload, baseAssetId);
return isDesiredInput ? calcOutputForExactInput(baseAssetId, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee) : calcInputForExactOutput(baseAssetId, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
const getFeeFromDestination = decideIsFeeFromDestination(baseAssetId, inputAsset, outputAsset);
return isDesiredInput ? calcOutputForExactInput(getFeeFromDestination, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee) : calcInputForExactOutput(getFeeFromDestination, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
} catch (error) {

@@ -236,0 +275,0 @@ return (0, _utils.safeQuoteResult)(inputAsset, outputAsset, amount, _consts.LiquiditySourceTypes.XYKPool);

@@ -35,2 +35,7 @@ "use strict";

// Get max amount for the limit
const limit = (0, _utils.toFp)(payload.consts.xst.syntheticBaseBuySellLimit);
if (limit.isZero()) return quotation;
quotation.limits.maxAmount = (0, _utils.isAssetAddress)(inputAsset, syntheticBaseAssetId) ? new _primitives.SideAmount(limit, _consts.SwapVariant.WithDesiredInput) : new _primitives.SideAmount(limit, _consts.SwapVariant.WithDesiredOutput);
// Get the price without checking the limit, because even if it exceeds the limit it will be rounded below.

@@ -45,6 +50,2 @@ // It is necessary to use as much liquidity from the source as we can.

// Get max amount for the limit
const limit = (0, _utils.toFp)(payload.consts.xst.syntheticBaseBuySellLimit);
quotation.limits.maxAmount = (0, _utils.isAssetAddress)(inputAsset, syntheticBaseAssetId) ? new _primitives.SideAmount(limit, _consts.SwapVariant.WithDesiredInput) : new _primitives.SideAmount(limit, _consts.SwapVariant.WithDesiredOutput);
// If amount exceeds the limit, it is necessary to round the amount to the limit.

@@ -51,0 +52,0 @@ if ((0, _utils.isAssetAddress)(inputAsset, syntheticBaseAssetId)) {

{
"name": "@sora-substrate/liquidity-proxy",
"version": "1.35.6",
"version": "1.35.7",
"license": "Apache-2.0",

@@ -11,5 +11,5 @@ "main": "./build/index.js",

"dependencies": {
"@sora-substrate/math": "1.35.6"
"@sora-substrate/math": "1.35.7"
},
"gitHead": "b7b25bf27e079d3717505b38bcb3141a3249fa1b"
"gitHead": "c3e9404856b29a6fd6967542c40110e98f4e4616"
}

@@ -26,2 +26,6 @@ import { FPNumber } from '@sora-substrate/math';

static readonly MAX = new FPNumber('170141183460469231731.687303715884105727');
/** Manimal significant balance */
static readonly MIN = FPNumber.fromCodecValue(1);
/** Irreducible reserve percent = 1% */
static readonly IrreducibleReserve = new FPNumber(0.01);

@@ -37,7 +41,11 @@ /** ETH & DAI which are incentivized */

export enum Errors {
PriceCalculationFailed = 'An error occurred while calculating the price.',
CalculationError = 'Specified parameters lead to arithmetic error',
CantExchange = "Liquidity source can't exchange assets with the given IDs on the given DEXId.",
PoolIsEmpty = 'The pool has empty liquidity.',
InsufficientLiquidity = 'None of the sources has enough reserves to execute a trade',
InvalidOrderAmount = 'Invalid Order Amount',
InvalidFeeRatio = 'Invalid fee ratio value.',
NotEnoughLiquidityInOrderBook = 'Not Enough Liquidity In OrderBook',
NotEnoughReserves = "It's not enough reserves in the pool to perform the operation.",
PoolIsEmpty = 'The pool has empty liquidity.',
PriceCalculationFailed = 'An error occurred while calculating the price.',
SyntheticDoesNotExist = 'Synthetic asset does not exist.',

@@ -47,4 +55,3 @@ SyntheticBaseBuySellLimitExceeded = 'Input/output amount of synthetic base asset exceeds the limit',

UnknownOrderBook = 'Order book does not exist for this trading pair',
NotEnoughLiquidityInOrderBook = 'Not Enough Liquidity In OrderBook',
InvalidOrderAmount = 'Invalid Order Amount',
UnsupportedQuotePath = 'Attempt to quote via unsupported path, i.e. both output and input tokens are not XOR.',
// own

@@ -51,0 +58,0 @@ UnsupportedLiquiditySource = 'Unsupported liquidity source',

import { FPNumber } from '@sora-substrate/math';
import { SwapVariant, LiquiditySourceTypes } from '../../consts';
import { SwapVariant, LiquiditySourceTypes, Errors } from '../../consts';
import { SwapChunk, DiscreteQuotation, SideAmount } from '../../common/primitives';

@@ -33,4 +33,4 @@ import { checkedSub } from '../../utils';

// Liquidity sources provide discretized liquidity curve by chunks and then Liquidity Aggregator selects the best chunks from different sources to gain the best swap amount.
public aggregateSwapOutcome(amount: FPNumber): AggregatedSwapOutcome | null {
if (!this.liquidityQuotations.size) return null;
public aggregateSwapOutcome(amount: FPNumber): AggregatedSwapOutcome {
if (!this.liquidityQuotations.size) throw new Error(Errors.InsufficientLiquidity);

@@ -45,3 +45,3 @@ let remainingAmount = amount;

let source = candidates[0];
if (!source) return null;
if (!source) throw new Error(Errors.InsufficientLiquidity);

@@ -58,5 +58,5 @@ // if there are several candidates with the same best price,

const discreteQuotation = this.liquidityQuotations.get(source);
if (!discreteQuotation) return null;
if (!discreteQuotation) throw new Error(Errors.InsufficientLiquidity);
let chunk = discreteQuotation.chunks.shift();
if (!chunk) return null;
if (!chunk) throw new Error(Errors.InsufficientLiquidity);
let payback = SwapChunk.zero();

@@ -99,3 +99,3 @@

const remainingSubResult = checkedSub(remainingAmount, remainingDelta);
if (!remainingSubResult) return null;
if (!remainingSubResult) throw new Error(Errors.CalculationError);
remainingAmount = remainingSubResult;

@@ -109,3 +109,3 @@

const discreteQuotation = this.liquidityQuotations.get(source);
if (!discreteQuotation) return null;
if (!discreteQuotation) throw new Error(Errors.InsufficientLiquidity);
const [aligned, remainder] = discreteQuotation.limits.alignChunk(total);

@@ -139,3 +139,3 @@

const value = checkedSub(remainderSide.amount, chunk.getAssociatedField(this.variant).amount);
if (!value) return null;
if (!value) throw new Error(Errors.CalculationError);
remainderSide.amount = value;

@@ -142,0 +142,0 @@ discreteQuotation.chunks.unshift(chunk);

@@ -335,6 +335,2 @@ import { FPNumber } from '@sora-substrate/math';

if (!result) {
throw new Error(Errors.UnavailableExchangePath);
}
const rewards = [];

@@ -341,0 +337,0 @@

@@ -51,4 +51,26 @@ import { FPNumber } from '@sora-substrate/math';

// reduce amount if it exceeds reserves
if (isAssetAddress(inputAsset, baseAssetId)) {
const collateralSupply = toFp(payload.reserves.tbc[outputAsset]);
if (collateralSupply.isZero()) return quotation;
const [adjustedAmount, maxLimit] = (() => {
if (!isDesiredInput) {
// reduce by `IrreducibleReserve` percent, because (reserve - output) must be > 0
const maxValue = saturatingSub(collateralSupply, Consts.IrreducibleReserve.mul(collateralSupply));
const value = maxValue.min(amount);
return [value, new SideAmount(maxValue, SwapVariant.WithDesiredOutput)];
} else {
return [amount, null];
}
})();
quotation.limits.maxAmount = maxLimit;
amount = adjustedAmount;
}
const samplesCount = recommendedSamplesCount < 1 ? 1 : recommendedSamplesCount;
const step = safeDivide(amount, new FPNumber(samplesCount));

@@ -87,16 +109,2 @@ const volumes = [];

if (isAssetAddress(inputAsset, baseAssetId)) {
const collateralSupply = toFp(payload.reserves.tbc[outputAsset]);
if (isDesiredInput) {
const mainPricePerReferenceUnit = sellFunction(inputAsset, outputAsset, FPNumber.ZERO, payload);
const collateralPricePerReferenceUnit = referencePrice(outputAsset, PriceVariant.Sell, payload);
const mainSupply = safeDivide(collateralSupply.mul(collateralPricePerReferenceUnit), mainPricePerReferenceUnit);
quotation.limits.maxAmount = new SideAmount(mainSupply, SwapVariant.WithDesiredInput);
} else {
quotation.limits.maxAmount = new SideAmount(collateralSupply, SwapVariant.WithDesiredOutput);
}
}
return quotation;

@@ -103,0 +111,0 @@ };

import { FPNumber } from '@sora-substrate/math';
import { LiquiditySourceTypes, Consts, Errors } from '../consts';
import { safeDivide, toFp, isAssetAddress, safeQuoteResult } from '../utils';
import { SwapChunk, DiscreteQuotation } from '../common/primitives';
import { LiquiditySourceTypes, Consts, Errors, SwapVariant } from '../consts';
import { safeDivide, toFp, isAssetAddress, safeQuoteResult, saturatingSub } from '../utils';
import { SwapChunk, DiscreteQuotation, SideAmount } from '../common/primitives';

@@ -26,2 +26,24 @@ import type { QuotePayload, QuoteResult } from '../types';

// decide_is_fee_from_destination
const decideIsFeeFromDestination = (baseAssetId: string, assetA: string, assetB: string) => {
if (isAssetAddress(baseAssetId, assetA)) {
return false;
} else if (isAssetAddress(baseAssetId, assetB)) {
return true;
} else {
throw new Error(Errors.UnavailableExchangePath);
}
};
// calc_max_output
const calcMaxOutput = (getFeeFromDestination: boolean, reserveOutput: FPNumber, deduceFee: boolean) => {
if (reserveOutput.isZero()) return FPNumber.ZERO;
const maxOutput =
getFeeFromDestination && deduceFee ? reserveOutput.mul(FPNumber.ONE.sub(Consts.XYK_FEE)) : reserveOutput;
// // reduce by `IrreducibleReserve` percent, because (reserve - output) must be > 0
return saturatingSub(maxOutput, Consts.IrreducibleReserve.mul(maxOutput));
};
// step_quote

@@ -55,5 +77,19 @@ export const stepQuote = (

) {
throw new Error(Errors.PoolIsEmpty);
return quotation;
}
const getFeeFromDestination = decideIsFeeFromDestination(baseAssetId, inputAsset, outputAsset);
amount = (() => {
if (isDesiredInput) {
return amount;
} else {
const maxOutput = calcMaxOutput(getFeeFromDestination, reserveOutput, deduceFee);
quotation.limits.maxAmount = new SideAmount(maxOutput, SwapVariant.WithDesiredOutput);
return maxOutput.min(amount);
}
})();
const commonStep = safeDivide(amount, new FPNumber(samplesCount));

@@ -70,3 +106,3 @@ // volume & step

remaining = remaining.sub(commonStep);
remaining = saturatingSub(remaining, commonStep);
}

@@ -81,3 +117,3 @@ volumes.push([amount, remaining]);

const { amount: calculated, fee } = calcOutputForExactInput(
baseAssetId,
getFeeFromDestination,
inputAsset,

@@ -91,4 +127,4 @@ outputAsset,

const output = calculated.sub(subSum);
const feeChunk = fee.sub(subFee);
const output = saturatingSub(calculated, subSum);
const feeChunk = saturatingSub(fee, subFee);
subSum = calculated;

@@ -101,3 +137,3 @@ subFee = fee;

const { amount: calculated, fee } = calcInputForExactOutput(
baseAssetId,
getFeeFromDestination,
inputAsset,

@@ -111,4 +147,4 @@ outputAsset,

const input = calculated.sub(subSum);
const feeChunk = fee.sub(subFee);
const input = saturatingSub(calculated, subSum);
const feeChunk = saturatingSub(fee, subFee);
subSum = calculated;

@@ -236,3 +272,3 @@ subFee = fee;

const fxwYout = yOut.add(FPNumber.fromCodecValue(1)); // by 1 correction to overestimate required input
const fxwYout = yOut.add(Consts.MIN); // by 1 correction to overestimate required input
const nominator = x.mul(fxwYout);

@@ -276,3 +312,3 @@ const denominator = y.sub(fxwYout);

): QuoteResult => {
const fxwYout = yOut.add(FPNumber.fromCodecValue(1)); // by 1 correction to overestimate required input
const fxwYout = yOut.add(Consts.MIN); // by 1 correction to overestimate required input
const yOutWithFee = deduceFee ? safeDivide(fxwYout, FPNumber.ONE.sub(Consts.XYK_FEE)) : fxwYout;

@@ -310,3 +346,3 @@

const calcOutputForExactInput = (
baseAssetId: string,
getFeeFromDestination: boolean,
inputAsset: string,

@@ -319,5 +355,7 @@ outputAsset: string,

) => {
return isAssetAddress(inputAsset, baseAssetId)
? xykQuoteA(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee)
: xykQuoteB(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
if (getFeeFromDestination) {
return xykQuoteB(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
} else {
return xykQuoteA(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
}
};

@@ -327,3 +365,3 @@

const calcInputForExactOutput = (
baseAssetId: string,
getFeeFromDestination: boolean,
inputAsset: string,

@@ -336,5 +374,7 @@ outputAsset: string,

) => {
return isAssetAddress(inputAsset, baseAssetId)
? xykQuoteC(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee)
: xykQuoteD(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
if (getFeeFromDestination) {
return xykQuoteD(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
} else {
return xykQuoteC(inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
}
};

@@ -358,6 +398,23 @@

const [inputReserves, outputReserves] = getXykReserves(inputAsset, outputAsset, payload, baseAssetId);
const getFeeFromDestination = decideIsFeeFromDestination(baseAssetId, inputAsset, outputAsset);
return isDesiredInput
? calcOutputForExactInput(baseAssetId, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee)
: calcInputForExactOutput(baseAssetId, inputAsset, outputAsset, inputReserves, outputReserves, amount, deduceFee);
? calcOutputForExactInput(
getFeeFromDestination,
inputAsset,
outputAsset,
inputReserves,
outputReserves,
amount,
deduceFee
)
: calcInputForExactOutput(
getFeeFromDestination,
inputAsset,
outputAsset,
inputReserves,
outputReserves,
amount,
deduceFee
);
} catch (error) {

@@ -364,0 +421,0 @@ return safeQuoteResult(inputAsset, outputAsset, amount, LiquiditySourceTypes.XYKPool);

@@ -53,2 +53,11 @@ import { FPNumber } from '@sora-substrate/math';

// Get max amount for the limit
const limit = toFp(payload.consts.xst.syntheticBaseBuySellLimit);
if (limit.isZero()) return quotation;
quotation.limits.maxAmount = isAssetAddress(inputAsset, syntheticBaseAssetId)
? new SideAmount(limit, SwapVariant.WithDesiredInput)
: new SideAmount(limit, SwapVariant.WithDesiredOutput);
// Get the price without checking the limit, because even if it exceeds the limit it will be rounded below.

@@ -64,8 +73,2 @@ // It is necessary to use as much liquidity from the source as we can.

// Get max amount for the limit
const limit = toFp(payload.consts.xst.syntheticBaseBuySellLimit);
quotation.limits.maxAmount = isAssetAddress(inputAsset, syntheticBaseAssetId)
? new SideAmount(limit, SwapVariant.WithDesiredInput)
: new SideAmount(limit, SwapVariant.WithDesiredOutput);
// If amount exceeds the limit, it is necessary to round the amount to the limit.

@@ -72,0 +75,0 @@ if (isAssetAddress(inputAsset, syntheticBaseAssetId)) {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc