@crocswap-libs/sdk
Version:
🛠🐊🛠 An SDK for building applications on top of CrocSwap
328 lines • 16.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CrocPoolView = void 0;
const tslib_1 = require("tslib");
const ethers_1 = require("ethers");
const context_1 = require("./context");
const flags_1 = require("./encoding/flags");
const init_1 = require("./encoding/init");
const liquidity_1 = require("./encoding/liquidity");
const tokens_1 = require("./tokens");
const utils_1 = require("./utils");
class CrocPoolView {
constructor(quoteToken, baseToken, context) {
[this.baseToken, this.quoteToken] =
(0, tokens_1.sortBaseQuoteViews)(baseToken, quoteToken);
this.context = context;
this.baseDecimals = this.baseToken.decimals;
this.quoteDecimals = this.quoteToken.decimals;
this.useTrueBase = this.baseToken.tokenAddr === baseToken.tokenAddr;
}
/* Checks to see if a canonical pool has been initialized for this pair. */
isInit() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return this.spotPrice()
.then(p => p > 0);
});
}
spotPrice(block) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let txArgs = block ? { blockTag: block } : {};
let sqrtPrice = (yield this.context).query.queryPrice.staticCall(this.baseToken.tokenAddr, this.quoteToken.tokenAddr, (yield this.context).chain.poolIndex, txArgs);
return (0, utils_1.decodeCrocPrice)(yield sqrtPrice);
});
}
displayPrice(block) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let spotPrice = this.spotPrice(block);
return this.toDisplayPrice(yield spotPrice);
});
}
spotTick(block) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let txArgs = block ? { blockTag: block } : {};
return (yield this.context).query.queryCurveTick.staticCall(this.baseToken.tokenAddr, this.quoteToken.tokenAddr, (yield this.context).chain.poolIndex, txArgs).then(Number);
});
}
xykLiquidity(block) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let txArgs = block ? { blockTag: block } : {};
return (yield this.context).query.queryLiquidity.staticCall(this.baseToken.tokenAddr, this.quoteToken.tokenAddr, (yield this.context).chain.poolIndex, txArgs);
});
}
curveState(block) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let txArgs = block ? { blockTag: block } : {};
return (yield this.context).query.queryCurve.staticCall(this.baseToken.tokenAddr, this.quoteToken.tokenAddr, (yield this.context).chain.poolIndex, txArgs);
});
}
cumAmbientGrowth(block) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const seedDeflator = (yield this.curveState(block)).seedDeflator_;
return (0, utils_1.bigIntToFloat)(seedDeflator) / Math.pow(2, 48);
});
}
toDisplayPrice(spotPrice) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return (0, utils_1.toDisplayPrice)(spotPrice, yield this.baseDecimals, yield this.quoteDecimals, !this.useTrueBase);
});
}
fromDisplayPrice(dispPrice) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return (0, utils_1.fromDisplayPrice)(dispPrice, yield this.baseDecimals, yield this.quoteDecimals, !this.useTrueBase);
});
}
displayToPinTick(dispPrice) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const spotPrice = yield this.fromDisplayPrice(dispPrice);
const gridSize = (yield this.context).chain.gridSize;
return [(0, utils_1.pinTickLower)(spotPrice, gridSize), (0, utils_1.pinTickUpper)(spotPrice, gridSize)];
});
}
displayToNeighborTicks(dispPrice_1) {
return tslib_1.__awaiter(this, arguments, void 0, function* (dispPrice, nNeighbors = 3) {
const spotPrice = yield this.fromDisplayPrice(dispPrice);
const gridSize = (yield this.context).chain.gridSize;
return (0, utils_1.neighborTicks)(spotPrice, gridSize, nNeighbors);
});
}
displayToNeighborTickPrices(dispPrice_1) {
return tslib_1.__awaiter(this, arguments, void 0, function* (dispPrice, nNeighbors = 3) {
const ticks = yield this.displayToNeighborTicks(dispPrice, nNeighbors);
const toPriceFn = (tick) => this.toDisplayPrice((0, utils_1.tickToPrice)(tick));
const belowPrices = Promise.all(ticks.below.map(toPriceFn));
const abovePrices = Promise.all(ticks.above.map(toPriceFn));
return this.useTrueBase ?
{ below: yield belowPrices, above: yield abovePrices } :
{ below: yield abovePrices, above: yield belowPrices };
});
}
displayToOutsidePin(dispPrice) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const spotPrice = this.fromDisplayPrice(dispPrice);
const gridSize = (yield this.context).chain.gridSize;
const pinTick = (0, utils_1.pinTickOutside)(yield spotPrice, yield this.spotPrice(), gridSize);
const pinPrice = this.toDisplayPrice((0, utils_1.tickToPrice)(pinTick.tick));
return Object.assign(pinTick, { price: yield pinPrice,
isPriceBelow: (yield pinPrice) < dispPrice });
});
}
initPool(initPrice) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
// Very small amount of ETH in economic terms but more than sufficient for min init burn
const ETH_INIT_BURN = BigInt(10) ** BigInt(12);
let txArgs = this.baseToken.tokenAddr === ethers_1.ZeroAddress ? { value: ETH_INIT_BURN } : {};
let encoder = new init_1.PoolInitEncoder(this.baseToken.tokenAddr, this.quoteToken.tokenAddr, (yield this.context).chain.poolIndex);
let spotPrice = this.fromDisplayPrice(initPrice);
let calldata = encoder.encodeInitialize(yield spotPrice);
let cntx = yield this.context;
yield (0, context_1.ensureChain)(cntx);
const gasEst = yield cntx.dex.userCmd.estimateGas(cntx.chain.proxyPaths.cold, calldata, txArgs);
Object.assign(txArgs, { gasLimit: gasEst + utils_1.GAS_PADDING, chainId: cntx.chain.chainId });
return cntx.dex.userCmd(cntx.chain.proxyPaths.cold, calldata, txArgs);
});
}
mintAmbientBase(qty, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return this.mintAmbient(qty, this.useTrueBase, limits, opts);
});
}
mintAmbientQuote(qty, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return this.mintAmbient(qty, !this.useTrueBase, limits, opts);
});
}
mintRangeBase(qty, range, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return this.mintRange(qty, this.useTrueBase, range, yield limits, opts);
});
}
mintRangeQuote(qty, range, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return this.mintRange(qty, !this.useTrueBase, range, yield limits, opts);
});
}
burnAmbientLiq(liq, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let [lowerBound, upperBound] = yield this.transformLimits(limits);
const calldata = (yield this.makeEncoder()).encodeBurnAmbient(liq, lowerBound, upperBound, this.maskSurplusFlag(opts));
return this.sendCmd(calldata);
});
}
burnAmbientAll(limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let [lowerBound, upperBound] = yield this.transformLimits(limits);
const calldata = (yield this.makeEncoder()).encodeBurnAmbientAll(lowerBound, upperBound, this.maskSurplusFlag(opts));
return this.sendCmd(calldata);
});
}
burnRangeLiq(liq, range, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let [lowerBound, upperBound] = yield this.transformLimits(limits);
let roundLotLiq = (0, utils_1.roundForConcLiq)(liq);
const calldata = (yield this.makeEncoder()).encodeBurnConc(range[0], range[1], roundLotLiq, lowerBound, upperBound, this.maskSurplusFlag(opts));
return this.sendCmd(calldata);
});
}
harvestRange(range, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let [lowerBound, upperBound] = yield this.transformLimits(limits);
const calldata = (yield this.makeEncoder()).encodeHarvestConc(range[0], range[1], lowerBound, upperBound, this.maskSurplusFlag(opts));
return this.sendCmd(calldata);
});
}
sendCmd(calldata, txArgs) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let cntx = yield this.context;
if (txArgs === undefined) {
txArgs = {};
}
yield (0, context_1.ensureChain)(cntx);
const gasEst = yield cntx.dex.userCmd.estimateGas(cntx.chain.proxyPaths.liq, calldata, txArgs);
Object.assign(txArgs, { gasLimit: gasEst + utils_1.GAS_PADDING, chainId: cntx.chain.chainId });
return cntx.dex.userCmd(cntx.chain.proxyPaths.liq, calldata, txArgs);
});
}
mintAmbient(qty, isQtyBase, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let msgVal = this.msgValAmbient(qty, isQtyBase, limits, opts);
let weiQty = this.normQty(qty, isQtyBase);
let [lowerBound, upperBound] = yield this.transformLimits(limits);
const calldata = (yield this.makeEncoder()).encodeMintAmbient(yield weiQty, isQtyBase, lowerBound, upperBound, this.maskSurplusFlag(opts));
return this.sendCmd(calldata, { value: yield msgVal });
});
}
boundLimits(range_1, limits_1, isQtyBase_1) {
return tslib_1.__awaiter(this, arguments, void 0, function* (range, limits, isQtyBase, floatingSlippage = 0.1) {
let spotPrice = this.spotPrice();
const [lowerPrice, upperPrice] = this.rangeToPrice(range);
const [boundLower, boundUpper] = yield this.transformLimits(limits);
const BOUND_PREC = 1.0001;
let [amplifyLower, amplifyUpper] = [boundLower, boundUpper];
if (upperPrice < (yield spotPrice)) {
amplifyLower = upperPrice * BOUND_PREC;
}
else if (lowerPrice > (yield spotPrice)) {
amplifyUpper = lowerPrice / BOUND_PREC;
}
else {
if (isQtyBase) {
amplifyLower = (0, utils_1.concBaseSlippagePrice)(yield spotPrice, upperPrice, floatingSlippage);
}
else {
amplifyUpper = (0, utils_1.concQuoteSlippagePrice)(yield spotPrice, lowerPrice, floatingSlippage);
}
}
return this.untransformLimits([Math.max(amplifyLower, boundLower), Math.min(amplifyUpper, boundUpper)]);
});
}
rangeToPrice(range) {
const lowerPrice = Math.pow(1.0001, range[0]);
const upperPrice = Math.pow(1.0001, range[1]);
return [lowerPrice, upperPrice];
}
transformLimits(limits) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let left = this.fromDisplayPrice(limits[0]);
let right = this.fromDisplayPrice(limits[1]);
return ((yield left) < (yield right)) ?
[yield left, yield right] :
[yield right, yield left];
});
}
untransformLimits(limits) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let left = this.toDisplayPrice(limits[0]);
let right = this.toDisplayPrice(limits[1]);
return ((yield left) < (yield right)) ?
[yield left, yield right] :
[yield right, yield left];
});
}
mintRange(qty, isQtyBase, range, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const saneLimits = yield this.boundLimits(range, limits, isQtyBase, opts === null || opts === void 0 ? void 0 : opts.floatingSlippage);
let msgVal = this.msgValRange(qty, isQtyBase, range, yield saneLimits, opts);
let weiQty = this.normQty(qty, isQtyBase);
let [lowerBound, upperBound] = yield this.transformLimits(yield saneLimits);
const calldata = (yield this.makeEncoder()).encodeMintConc(range[0], range[1], yield weiQty, isQtyBase, lowerBound, upperBound, this.maskSurplusFlag(opts));
return this.sendCmd(calldata, { value: yield msgVal });
});
}
maskSurplusFlag(opts) {
if (!opts || opts.surplus === undefined) {
return this.maskSurplusFlag({ surplus: false });
}
return (0, flags_1.encodeSurplusArg)(opts.surplus, this.useTrueBase);
}
msgValAmbient(qty, isQtyBase, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let ethQty = isQtyBase ? qty :
this.ethForAmbientQuote(qty, limits);
return this.ethToAttach(yield ethQty, opts);
});
}
msgValRange(qty, isQtyBase, range, limits, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let ethQty = isQtyBase ? qty :
this.ethForRangeQuote(qty, range, limits);
return this.ethToAttach(yield ethQty, opts);
});
}
ethToAttach(neededQty, opts) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (this.baseToken.tokenAddr !== ethers_1.ZeroAddress) {
return BigInt(0);
}
const ethQty = yield this.normEth(neededQty);
let useSurplus = (0, flags_1.decodeSurplusFlag)(this.maskSurplusFlag(opts))[0];
if (useSurplus) {
return new tokens_1.CrocEthView(this.context).msgValOverSurplus(ethQty);
}
else {
return ethQty;
}
});
}
ethForAmbientQuote(quoteQty, limits) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const weiEth = this.calcEthInQuote(quoteQty, limits);
return (0, utils_1.toDisplayQty)(yield weiEth, yield this.baseDecimals);
});
}
calcEthInQuote(quoteQty_1, limits_1) {
return tslib_1.__awaiter(this, arguments, void 0, function* (quoteQty, limits, precAdj = 1.001) {
const weiQty = yield this.normQty(quoteQty, false);
const [, boundPrice] = yield this.transformLimits(limits);
return Math.round((0, utils_1.bigIntToFloat)(weiQty) * boundPrice * precAdj);
});
}
ethForRangeQuote(quoteQty, range, limits) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
const spotPrice = yield this.spotPrice();
const [lowerPrice, upperPrice] = this.rangeToPrice(range);
let skew = (0, utils_1.concDepositSkew)(spotPrice, lowerPrice, upperPrice);
let ambiQty = this.calcEthInQuote(quoteQty, limits);
let concQty = ambiQty.then(aq => Math.ceil(aq * skew));
return (0, utils_1.toDisplayQty)(yield concQty, yield this.baseDecimals);
});
}
normEth(ethQty) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return this.normQty(ethQty, true); // ETH is always on base side
});
}
normQty(qty, isBase) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
let token = isBase ? this.baseToken : this.quoteToken;
return token.normQty(qty);
});
}
makeEncoder() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
return new liquidity_1.WarmPathEncoder(this.baseToken.tokenAddr, this.quoteToken.tokenAddr, (yield this.context).chain.poolIndex);
});
}
}
exports.CrocPoolView = CrocPoolView;
//# sourceMappingURL=pool.js.map