@drift-labs/sdk
Version:
SDK for Drift Protocol
165 lines (164 loc) • 6.62 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.calculateBudgetedPeg = exports.calculateBudgetedK = exports.calculateBudgetedKBN = exports.calculateRepegCost = exports.calculateAdjustKCost = void 0;
const anchor_1 = require("@coral-xyz/anchor");
const assert_1 = require("../assert/assert");
const numericConstants_1 = require("../constants/numericConstants");
/**
* Helper function calculating adjust k cost
* @param amm
* @param numerator
* @param denomenator
* @returns cost : Precision QUOTE_ASSET_PRECISION
*/
function calculateAdjustKCost(amm, numerator, denomenator) {
// const k = market.amm.sqrtK.mul(market.amm.sqrtK);
const x = amm.baseAssetReserve;
const y = amm.quoteAssetReserve;
const d = amm.baseAssetAmountWithAmm;
const Q = amm.pegMultiplier;
const quoteScale = y.mul(d).mul(Q); //.div(AMM_RESERVE_PRECISION);
const p = numerator.mul(numericConstants_1.PRICE_PRECISION).div(denomenator);
const cost = quoteScale
.mul(numericConstants_1.PERCENTAGE_PRECISION)
.mul(numericConstants_1.PERCENTAGE_PRECISION)
.div(x.add(d))
.sub(quoteScale
.mul(p)
.mul(numericConstants_1.PERCENTAGE_PRECISION)
.mul(numericConstants_1.PERCENTAGE_PRECISION)
.div(numericConstants_1.PRICE_PRECISION)
.div(x.mul(p).div(numericConstants_1.PRICE_PRECISION).add(d)))
.div(numericConstants_1.PERCENTAGE_PRECISION)
.div(numericConstants_1.PERCENTAGE_PRECISION)
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
.div(numericConstants_1.PEG_PRECISION);
return cost.mul(new anchor_1.BN(-1));
}
exports.calculateAdjustKCost = calculateAdjustKCost;
// /**
// * Helper function calculating adjust k cost
// * @param amm
// * @param numerator
// * @param denomenator
// * @returns cost : Precision QUOTE_ASSET_PRECISION
// */
// export function calculateAdjustKCost2(
// amm: AMM,
// numerator: BN,
// denomenator: BN
// ): BN {
// // const k = market.amm.sqrtK.mul(market.amm.sqrtK);
// const directionToClose = amm.baseAssetAmountWithAmm.gt(ZERO)
// ? PositionDirection.SHORT
// : PositionDirection.LONG;
// const [newQuoteAssetReserve, _newBaseAssetReserve] =
// calculateAmmReservesAfterSwap(
// amm,
// 'base',
// amm.baseAssetAmountWithAmm.abs(),
// getSwapDirection('base', directionToClose)
// );
// }
/**
* Helper function calculating adjust pegMultiplier (repeg) cost
*
* @param amm
* @param newPeg
* @returns cost : Precision QUOTE_ASSET_PRECISION
*/
function calculateRepegCost(amm, newPeg) {
const dqar = amm.quoteAssetReserve.sub(amm.terminalQuoteAssetReserve);
const cost = dqar
.mul(newPeg.sub(amm.pegMultiplier))
.div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO)
.div(numericConstants_1.PEG_PRECISION);
return cost;
}
exports.calculateRepegCost = calculateRepegCost;
function calculateBudgetedKBN(x, y, budget, Q, d) {
(0, assert_1.assert)(Q.gt(new anchor_1.BN(0)));
const C = budget.mul(new anchor_1.BN(-1));
let dSign = new anchor_1.BN(1);
if (d.lt(new anchor_1.BN(0))) {
dSign = new anchor_1.BN(-1);
}
const pegged_y_d_d = y
.mul(d)
.mul(d)
.mul(Q)
.div(numericConstants_1.AMM_RESERVE_PRECISION)
.div(numericConstants_1.AMM_RESERVE_PRECISION)
.div(numericConstants_1.PEG_PRECISION);
const numer1 = pegged_y_d_d;
const numer2 = C.mul(d)
.div(numericConstants_1.QUOTE_PRECISION)
.mul(x.add(d))
.div(numericConstants_1.AMM_RESERVE_PRECISION)
.mul(dSign);
const denom1 = C.mul(x)
.mul(x.add(d))
.div(numericConstants_1.AMM_RESERVE_PRECISION)
.div(numericConstants_1.QUOTE_PRECISION);
const denom2 = pegged_y_d_d;
// protocol is spending to increase k
if (C.lt(numericConstants_1.ZERO)) {
// thus denom1 is negative and solution is unstable
if (denom1.abs().gt(denom2.abs())) {
console.log('denom1 > denom2', denom1.toString(), denom2.toString());
console.log('budget cost exceeds stable K solution');
return [new anchor_1.BN(10000), new anchor_1.BN(1)];
}
}
const numerator = numer1.sub(numer2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
const denominator = denom1.add(denom2).div(numericConstants_1.AMM_TO_QUOTE_PRECISION_RATIO);
return [numerator, denominator];
}
exports.calculateBudgetedKBN = calculateBudgetedKBN;
function calculateBudgetedK(amm, cost) {
// wolframalpha.com
// (1/(x+d) - p/(x*p+d))*y*d*Q = C solve for p
// p = (d(y*d*Q - C(x+d))) / (C*x(x+d) + y*d*d*Q)
// numer
// = y*d*d*Q - Cxd - Cdd
// = y/x*Q*d*d - Cd - Cd/x
// = mark - C/d - C/(x)
// = mark/C - 1/d - 1/x
// denom
// = C*x*x + C*x*d + y*d*d*Q
// = x/d**2 + 1 / d + mark/C
// todo: assumes k = x * y
// otherwise use: (y(1-p) + (kp^2/(x*p+d)) - k/(x+d)) * Q = C solve for p
const x = amm.baseAssetReserve;
const y = amm.quoteAssetReserve;
const d = amm.baseAssetAmountWithAmm;
const Q = amm.pegMultiplier;
const [numerator, denominator] = calculateBudgetedKBN(x, y, cost, Q, d);
return [numerator, denominator];
}
exports.calculateBudgetedK = calculateBudgetedK;
function calculateBudgetedPeg(amm, budget, targetPrice) {
let perPegCost = amm.quoteAssetReserve
.sub(amm.terminalQuoteAssetReserve)
.div(numericConstants_1.AMM_RESERVE_PRECISION.div(numericConstants_1.PRICE_PRECISION));
if (perPegCost.gt(numericConstants_1.ZERO)) {
perPegCost = perPegCost.add(numericConstants_1.ONE);
}
else if (perPegCost.lt(numericConstants_1.ZERO)) {
perPegCost = perPegCost.sub(numericConstants_1.ONE);
}
const targetPeg = targetPrice
.mul(amm.baseAssetReserve)
.div(amm.quoteAssetReserve)
.div(numericConstants_1.PRICE_DIV_PEG);
const pegChangeDirection = targetPeg.sub(amm.pegMultiplier);
const useTargetPeg = (perPegCost.lt(numericConstants_1.ZERO) && pegChangeDirection.gt(numericConstants_1.ZERO)) ||
(perPegCost.gt(numericConstants_1.ZERO) && pegChangeDirection.lt(numericConstants_1.ZERO));
if (perPegCost.eq(numericConstants_1.ZERO) || useTargetPeg) {
return targetPeg;
}
const budgetDeltaPeg = budget.mul(numericConstants_1.PEG_PRECISION).div(perPegCost);
const newPeg = anchor_1.BN.max(numericConstants_1.ONE, amm.pegMultiplier.add(budgetDeltaPeg));
return newPeg;
}
exports.calculateBudgetedPeg = calculateBudgetedPeg;